Effect provides options to manage how effects are executed, particularly focusing on controlling how many effects run concurrently.
The concurrency option is used to determine the level of concurrency, with the following values:
Let’s explore each configuration in detail.
Sequential Execution (Default)
By default, if you don’t specify any concurrency option, effects will run sequentially, one after the other. This means each effect starts only after the previous one completes.
Example (Sequential Execution)
Numbered Concurrency
You can control how many effects run concurrently by setting a number for concurrency. For example, concurrency: 2 allows up to two effects to run at the same time.
Example (Limiting to 2 Concurrent Tasks)
Unbounded Concurrency
When concurrency: "unbounded" is used, there’s no limit to the number of effects running concurrently.
Example (Unbounded Concurrency)
Inherit Concurrency
When using concurrency: "inherit", the concurrency level is inherited from the surrounding context. This context can be set using Effect.withConcurrency(number | "unbounded"). If no context is provided, the default is "unbounded".
Example (Inheriting Concurrency from Context)
If you use Effect.withConcurrency, the concurrency configuration will adjust to the specified option.
Example (Setting Concurrency Option)
Interruptions
All effects in Effect are executed by fibers. If you didn’t create the fiber yourself, it was created by an operation you’re using (if it’s concurrent) or by the Effect runtime system.
A fiber is created any time an effect is run. When running effects concurrently, a fiber is created for each concurrent effect.
To summarize:
An Effect is a higher-level concept that describes an effectful computation. It is lazy and immutable, meaning it represents a computation that may produce a value or fail but does not immediately execute.
A fiber, on the other hand, represents the running execution of an Effect. It can be interrupted or awaited to retrieve its result. Think of it as a way to control and interact with the ongoing computation.
Fibers can be interrupted in various ways. Let’s explore some of these scenarios and see examples of how to interrupt fibers in Effect.
Effect.interrupt
A fiber can be interrupted using the Effect.interrupt effect on that particular fiber.
Example (Without Interruption)
In this case, the program runs without any interruption, logging the start and completion of the task.
Example (With Interruption)
Here, the fiber is interrupted after the log "start" but before the "done" log. The Effect.interrupt stops the fiber, and it never reaches the final log.
When a fiber is interrupted, the cause of the interruption is captured, including details like the fiber’s ID and when it started.
Interruption of Concurrent Effects
When running multiple effects concurrently, such as with Effect.forEach, if one of the effects is interrupted, it causes all concurrent effects to be interrupted as well.
Example (Interrupting Concurrent Effects)
Racing
The Effect.race function allows you to run multiple effects concurrently, returning the result of the first one that successfully completes.
Example (Basic Race Between Effects)
If you want to handle the result of whichever task completes first, whether it succeeds or fails, you can use the Effect.either function. This function wraps the result in an Either type, allowing you to see if the result was a success (Right) or a failure (Left):