Unexpected Errors
There are situations where you may encounter unexpected errors, and you need to decide how to handle them. Effect provides functions to help you deal with such scenarios, allowing you to take appropriate actions when errors occur during the execution of your effects.
In the same way it is possible to leverage combinators such as Effect.fail to create values of type Effect<never, E, never>
the Effect library provides tools to create defects.
Creating defects is a common necessity when dealing with errors from which it is not possible to recover from a business logic perspective, such as attempting to establish a connection that is refused after multiple retries.
In those cases terminating the execution of the effect and moving into reporting, through an output such as stdout or some external monitoring service, might be the best solution.
The following functions and combinators allow for termination of the effect and are often used to convert values of type Effect<A, E, R>
into values of type Effect<A, never, R>
allowing the programmer an escape hatch from having to handle and recover from errors for which there is no sensible way to recover.
The Effect.die
function returns an effect that throws a specified error, while Effect.dieMessage
throws a RuntimeException
with a specified text message. These functions are useful for terminating a fiber when a defect, a critical and unexpected error, is detected in the code.
Example (Terminating on Division by Zero with Effect.die
)
Example (Returning a RuntimeException with Effect.dieMessage
)
The Effect.orDie
function converts an effect’s failure into a termination of the fiber, removing the error from the type of the effect. It is useful when you encounter failures that you do not intend to handle or recover from.
Example (Converting Failure to Defect with Effect.orDie
)
After using Effect.orDie
, the error channel type of the program
is never
, meaning that the effect no longer handles failures, and will terminate the fiber when an error occurs.
Similar to Effect.orDie
, the Effect.orDieWith
function transforms an effect’s failure into a termination of the fiber using a specified mapping function. It allows you to customize the error message before terminating the fiber.
Example (Customizing Defect Message with Effect.orDieWith
)
After using Effect.orDieWith
, the error channel type of the program
is never
, just like with Effect.orDie
.
There is no sensible way to recover from defects. The functions we’re about to discuss should be used only at the boundary between Effect and an external system, to transmit information on a defect for diagnostic or explanatory purposes.
The Effect.exit
function transforms an Effect<A, E, R>
into an effect that encapsulates both potential failure and success within an Exit data type:
The resulting effect cannot fail because the potential failure is now represented within the Exit
’s Failure
type.
The error type of the returned effect is specified as never
, confirming that the effect is structured to not fail.
By yielding an Exit
, we gain the ability to “pattern match” on this type to handle both failure and success cases within the generator function.
Example (Catching Defects with Effect.exit
)
The Effect.catchAllDefect
function allows you to recover from all defects using a provided function.
Example (Handling All Defects with Effect.catchAllDefect
)
It’s important to understand that catchAllDefect
can only handle defects, not expected errors (such as those caused by Effect.fail
) or interruptions in execution (such as when using Effect.interrupt
).
A defect refers to an error that cannot be anticipated in advance, and there is no reliable way to respond to it. As a general rule, it’s recommended to let defects crash the application, as they often indicate serious issues that need to be addressed.
However, in some specific cases, such as when dealing with dynamically loaded plugins, a controlled recovery approach might be necessary. For example, if our application supports runtime loading of plugins and a defect occurs within a plugin, we may choose to log the defect and then reload only the affected plugin instead of crashing the entire application. This allows for a more resilient and uninterrupted operation of the application.
The Effect.catchSomeDefect
function in Effect allows you to recover from specific defects using a provided partial function.
Example (Handling Specific Defects with Effect.catchSomeDefect
)
It’s important to understand that catchSomeDefect
can only handle defects, not expected errors (such as those caused by Effect.fail
) or interruptions in execution (such as when using Effect.interrupt
).