Patterns
In certain scenarios, you might need to perform a sequence of chained operations where the success of each operation depends on the previous one. However, if any of the operations fail, you would want to reverse the effects of all previous successful operations. This pattern is valuable when you need to ensure that either all operations succeed, or none of them have any effect at all.
Effect offers a way to achieve this pattern using the Effect.acquireRelease function in combination with the Exit type. The Effect.acquireRelease function allows you to acquire a resource, perform operations with it, and release the resource when you’re done. The Exit type represents the outcome of an effectful computation, indicating whether it succeeded or failed.
Let’s go through an example of implementing this pattern. Suppose we want to create a “Workspace” in our application, which involves creating an S3 bucket, an ElasticSearch index, and a Database entry that relies on the previous two.
To begin, we define the domain model for the required services:
S3
ElasticSearch
Database
1import { import Effect
Effect, import Context
Context } from "effect"2
3class class S3Error
S3Error {4 readonly (property) S3Error._tag: "S3Error"
_tag = "S3Error"5}6
7interface interface Bucket
Bucket {8 readonly (property) Bucket.name: string
name: string9}10
11class class S3
S3 extends import Context
Context.const Tag: <"S3">(id: "S3") => <Self, Shape>() => Context.TagClass<Self, "S3", Shape>
namespace Tag
Tag("S3")<12 class S3
S3,13 {14 readonly (property) createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Bucket
Bucket, class S3Error
S3Error>15 readonly (property) deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket: ((parameter) bucket: Bucket
bucket: interface Bucket
Bucket) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>16 }17>() {}18
19class class ElasticSearchError
ElasticSearchError {20 readonly (property) ElasticSearchError._tag: "ElasticSearchError"
_tag = "ElasticSearchError"21}22
23interface interface Index
Index {24 readonly (property) Index.id: string
id: string25}26
27class class ElasticSearch
ElasticSearch extends import Context
Context.const Tag: <"ElasticSearch">(id: "ElasticSearch") => <Self, Shape>() => Context.TagClass<Self, "ElasticSearch", Shape>
namespace Tag
Tag("ElasticSearch")<28 class ElasticSearch
ElasticSearch,29 {30 readonly (property) createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Index
Index, class ElasticSearchError
ElasticSearchError>31 readonly (property) deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex: ((parameter) index: Index
index: interface Index
Index) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>32 }33>() {}34
35class class DatabaseError
DatabaseError {36 readonly (property) DatabaseError._tag: "DatabaseError"
_tag = "DatabaseError"37}38
39interface interface Entry
Entry {40 readonly (property) Entry.id: string
id: string41}42
43class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<44 class Database
Database,45 {46 readonly (property) createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry: (47 (parameter) bucket: Bucket
bucket: interface Bucket
Bucket,48 (parameter) index: Index
index: interface Index
Index49 ) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Entry
Entry, class DatabaseError
DatabaseError>50 readonly (property) deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry: ((parameter) entry: Entry
entry: interface Entry
Entry) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>51 }52>() {}
Next, we define the three create actions and the overall transaction (make
) for the
1import { import Effect
Effect, import Context
Context, import Exit
Exit } from "effect"2
50 collapsed lines
3class class S3Error
S3Error {4 readonly (property) S3Error._tag: "S3Error"
_tag = "S3Error"5}6
7interface interface Bucket
Bucket {8 readonly (property) Bucket.name: string
name: string9}10
11class class S3
S3 extends import Context
Context.const Tag: <"S3">(id: "S3") => <Self, Shape>() => Context.TagClass<Self, "S3", Shape>
namespace Tag
Tag("S3")<12 class S3
S3,13 {14 readonly (property) createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Bucket
Bucket, class S3Error
S3Error>15 readonly (property) deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket: ((parameter) bucket: Bucket
bucket: interface Bucket
Bucket) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>16 }17>() {}18
19class class ElasticSearchError
ElasticSearchError {20 readonly (property) ElasticSearchError._tag: "ElasticSearchError"
_tag = "ElasticSearchError"21}22
23interface interface Index
Index {24 readonly (property) Index.id: string
id: string25}26
27class class ElasticSearch
ElasticSearch extends import Context
Context.const Tag: <"ElasticSearch">(id: "ElasticSearch") => <Self, Shape>() => Context.TagClass<Self, "ElasticSearch", Shape>
namespace Tag
Tag("ElasticSearch")<28 class ElasticSearch
ElasticSearch,29 {30 readonly (property) createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Index
Index, class ElasticSearchError
ElasticSearchError>31 readonly (property) deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex: ((parameter) index: Index
index: interface Index
Index) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>32 }33>() {}34
35class class DatabaseError
DatabaseError {36 readonly (property) DatabaseError._tag: "DatabaseError"
_tag = "DatabaseError"37}38
39interface interface Entry
Entry {40 readonly (property) Entry.id: string
id: string41}42
43class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<44 class Database
Database,45 {46 readonly (property) createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry: (47 (parameter) bucket: Bucket
bucket: interface Bucket
Bucket,48 (parameter) index: Index
index: interface Index
Index49 ) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Entry
Entry, class DatabaseError
DatabaseError>50 readonly (property) deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry: ((parameter) entry: Entry
entry: interface Entry
Entry) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>51 }52>() {}53
54// Create a bucket, and define the release function that deletes the55// bucket if the operation fails.56const const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket = import Effect
Effect.const gen: <YieldWrap<Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>> | YieldWrap<...>, Bucket>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {57 const { const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket, const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket } = yield* class S3
S358 return yield* import Effect
Effect.const acquireRelease: <Bucket, S3Error, never, void, never>(acquire: Effect.Effect<Bucket, S3Error, never>, release: (a: Bucket, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
This function constructs a scoped resource from an `acquire` and `release`
`Effect` value.
If the `acquire` `Effect` value successfully completes execution, then the
`release` `Effect` value will be added to the finalizers associated with the
scope of this `Effect` value, and it is guaranteed to be run when the scope
is closed.
The `acquire` and `release` `Effect` values will be run uninterruptibly.
Additionally, the `release` `Effect` value may depend on the `Exit` value
specified when the scope is closed.
acquireRelease(const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket, ((parameter) bucket: Bucket
bucket, (parameter) exit: Exit.Exit<unknown, unknown>
exit) =>59 // The release function for the Effect.acquireRelease operation is60 // responsible for handling the acquired resource (bucket) after the61 // main effect has completed. It is called regardless of whether the62 // main effect succeeded or failed. If the main effect failed,63 // Exit.isFailure(exit) will be true, and the function will perform64 // a rollback by calling deleteBucket(bucket). If the main effect65 // succeeded, Exit.isFailure(exit) will be false, and the function66 // will return Effect.void, representing a successful, but67 // do-nothing effect.68 import Exit
Exit.const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>
Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise.
isFailure((parameter) exit: Exit.Exit<unknown, unknown>
exit) ? const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket((parameter) bucket: Bucket
bucket) : import Effect
Effect.(alias) const void: Effect.Effect<void, never, never>
export void
void69 )70})71
72// Create an index, and define the release function that deletes the73// index if the operation fails.74const const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex = import Effect
Effect.const gen: <YieldWrap<Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>> | YieldWrap<...>, Index>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {75 const { const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex, const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex } = yield* class ElasticSearch
ElasticSearch76 return yield* import Effect
Effect.const acquireRelease: <Index, ElasticSearchError, never, void, never>(acquire: Effect.Effect<Index, ElasticSearchError, never>, release: (a: Index, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
This function constructs a scoped resource from an `acquire` and `release`
`Effect` value.
If the `acquire` `Effect` value successfully completes execution, then the
`release` `Effect` value will be added to the finalizers associated with the
scope of this `Effect` value, and it is guaranteed to be run when the scope
is closed.
The `acquire` and `release` `Effect` values will be run uninterruptibly.
Additionally, the `release` `Effect` value may depend on the `Exit` value
specified when the scope is closed.
acquireRelease(const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex, ((parameter) index: Index
index, (parameter) exit: Exit.Exit<unknown, unknown>
exit) =>77 import Exit
Exit.const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>
Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise.
isFailure((parameter) exit: Exit.Exit<unknown, unknown>
exit) ? const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex((parameter) index: Index
index) : import Effect
Effect.(alias) const void: Effect.Effect<void, never, never>
export void
void78 )79})80
81// Create an entry in the database, and define the release function that82// deletes the entry if the operation fails.83const const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry = ((parameter) bucket: Bucket
bucket: interface Bucket
Bucket, (parameter) index: Index
index: interface Index
Index) =>84 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>> | YieldWrap<...>, Entry>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {85 const { const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry, const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry } = yield* class Database
Database86 return yield* import Effect
Effect.const acquireRelease: <Entry, DatabaseError, never, void, never>(acquire: Effect.Effect<Entry, DatabaseError, never>, release: (a: Entry, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
This function constructs a scoped resource from an `acquire` and `release`
`Effect` value.
If the `acquire` `Effect` value successfully completes execution, then the
`release` `Effect` value will be added to the finalizers associated with the
scope of this `Effect` value, and it is guaranteed to be run when the scope
is closed.
The `acquire` and `release` `Effect` values will be run uninterruptibly.
Additionally, the `release` `Effect` value may depend on the `Exit` value
specified when the scope is closed.
acquireRelease(87 const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry((parameter) bucket: Bucket
bucket, (parameter) index: Index
index),88 ((parameter) entry: Entry
entry, (parameter) exit: Exit.Exit<unknown, unknown>
exit) =>89 import Exit
Exit.const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>
Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise.
isFailure((parameter) exit: Exit.Exit<unknown, unknown>
exit) ? const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry((parameter) entry: Entry
entry) : import Effect
Effect.(alias) const void: Effect.Effect<void, never, never>
export void
void90 )91 })92
93const const make: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>
make = import Effect
Effect.const scoped: <Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database | Scope>(effect: Effect.Effect<...>) => Effect.Effect<...>
Scopes all resources used in this workflow to the lifetime of the workflow,
ensuring that their finalizers are run as soon as this workflow completes
execution, whether by success, failure, or interruption.
scoped(94 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Bucket, S3Error, S3 | Scope>> | YieldWrap<Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>> | YieldWrap<...>, Entry>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {95 const const bucket: Bucket
bucket = yield* const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket96 const const index: Index
index = yield* const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex97 return yield* const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry(const bucket: Bucket
bucket, const index: Index
index)98 })99)
We then create simple service implementations to test the behavior of our Workspace code.
To achieve this, we will utilize layers to construct test
These layers will be able to handle various scenarios, including errors, which we can control using the FailureCase
type.
1import { import Effect
Effect, import Context
Context, import Layer
Layer, import Console
Console, import Exit
Exit } from "effect"2
97 collapsed lines
3class class S3Error
S3Error {4 readonly (property) S3Error._tag: "S3Error"
_tag = "S3Error"5}6
7interface interface Bucket
Bucket {8 readonly (property) Bucket.name: string
name: string9}10
11class class S3
S3 extends import Context
Context.const Tag: <"S3">(id: "S3") => <Self, Shape>() => Context.TagClass<Self, "S3", Shape>
namespace Tag
Tag("S3")<12 class S3
S3,13 {14 readonly (property) createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Bucket
Bucket, class S3Error
S3Error>15 readonly (property) deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket: ((parameter) bucket: Bucket
bucket: interface Bucket
Bucket) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>16 }17>() {}18
19class class ElasticSearchError
ElasticSearchError {20 readonly (property) ElasticSearchError._tag: "ElasticSearchError"
_tag = "ElasticSearchError"21}22
23interface interface Index
Index {24 readonly (property) Index.id: string
id: string25}26
27class class ElasticSearch
ElasticSearch extends import Context
Context.const Tag: <"ElasticSearch">(id: "ElasticSearch") => <Self, Shape>() => Context.TagClass<Self, "ElasticSearch", Shape>
namespace Tag
Tag("ElasticSearch")<28 class ElasticSearch
ElasticSearch,29 {30 readonly (property) createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Index
Index, class ElasticSearchError
ElasticSearchError>31 readonly (property) deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex: ((parameter) index: Index
index: interface Index
Index) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>32 }33>() {}34
35class class DatabaseError
DatabaseError {36 readonly (property) DatabaseError._tag: "DatabaseError"
_tag = "DatabaseError"37}38
39interface interface Entry
Entry {40 readonly (property) Entry.id: string
id: string41}42
43class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<44 class Database
Database,45 {46 readonly (property) createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry: (47 (parameter) bucket: Bucket
bucket: interface Bucket
Bucket,48 (parameter) index: Index
index: interface Index
Index49 ) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<interface Entry
Entry, class DatabaseError
DatabaseError>50 readonly (property) deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry: ((parameter) entry: Entry
entry: interface Entry
Entry) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>51 }52>() {}53
54// Create a bucket, and define the release function that deletes the55// bucket if the operation fails.56const const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket = import Effect
Effect.const gen: <YieldWrap<Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>> | YieldWrap<...>, Bucket>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {57 const { const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket, const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket } = yield* class S3
S358 return yield* import Effect
Effect.const acquireRelease: <Bucket, S3Error, never, void, never>(acquire: Effect.Effect<Bucket, S3Error, never>, release: (a: Bucket, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
This function constructs a scoped resource from an `acquire` and `release`
`Effect` value.
If the `acquire` `Effect` value successfully completes execution, then the
`release` `Effect` value will be added to the finalizers associated with the
scope of this `Effect` value, and it is guaranteed to be run when the scope
is closed.
The `acquire` and `release` `Effect` values will be run uninterruptibly.
Additionally, the `release` `Effect` value may depend on the `Exit` value
specified when the scope is closed.
acquireRelease(const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket, ((parameter) bucket: Bucket
bucket, (parameter) exit: Exit.Exit<unknown, unknown>
exit) =>59 // The release function for the Effect.acquireRelease operation is60 // responsible for handling the acquired resource (bucket) after the61 // main effect has completed. It is called regardless of whether the62 // main effect succeeded or failed. If the main effect failed,63 // Exit.isFailure(exit) will be true, and the function will perform64 // a rollback by calling deleteBucket(bucket). If the main effect65 // succeeded, Exit.isFailure(exit) will be false, and the function66 // will return Effect.void, representing a successful, but67 // do-nothing effect.68 import Exit
Exit.const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>
Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise.
isFailure((parameter) exit: Exit.Exit<unknown, unknown>
exit) ? const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket((parameter) bucket: Bucket
bucket) : import Effect
Effect.(alias) const void: Effect.Effect<void, never, never>
export void
void69 )70})71
72// Create an index, and define the release function that deletes the73// index if the operation fails.74const const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex = import Effect
Effect.const gen: <YieldWrap<Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>> | YieldWrap<...>, Index>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {75 const { const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex, const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex } = yield* class ElasticSearch
ElasticSearch76 return yield* import Effect
Effect.const acquireRelease: <Index, ElasticSearchError, never, void, never>(acquire: Effect.Effect<Index, ElasticSearchError, never>, release: (a: Index, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
This function constructs a scoped resource from an `acquire` and `release`
`Effect` value.
If the `acquire` `Effect` value successfully completes execution, then the
`release` `Effect` value will be added to the finalizers associated with the
scope of this `Effect` value, and it is guaranteed to be run when the scope
is closed.
The `acquire` and `release` `Effect` values will be run uninterruptibly.
Additionally, the `release` `Effect` value may depend on the `Exit` value
specified when the scope is closed.
acquireRelease(const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex, ((parameter) index: Index
index, (parameter) exit: Exit.Exit<unknown, unknown>
exit) =>77 import Exit
Exit.const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>
Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise.
isFailure((parameter) exit: Exit.Exit<unknown, unknown>
exit) ? const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex((parameter) index: Index
index) : import Effect
Effect.(alias) const void: Effect.Effect<void, never, never>
export void
void78 )79})80
81// Create an entry in the database, and define the release function that82// deletes the entry if the operation fails.83const const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry = ((parameter) bucket: Bucket
bucket: interface Bucket
Bucket, (parameter) index: Index
index: interface Index
Index) =>84 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>> | YieldWrap<...>, Entry>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {85 const { const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry, const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry } = yield* class Database
Database86 return yield* import Effect
Effect.const acquireRelease: <Entry, DatabaseError, never, void, never>(acquire: Effect.Effect<Entry, DatabaseError, never>, release: (a: Entry, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
This function constructs a scoped resource from an `acquire` and `release`
`Effect` value.
If the `acquire` `Effect` value successfully completes execution, then the
`release` `Effect` value will be added to the finalizers associated with the
scope of this `Effect` value, and it is guaranteed to be run when the scope
is closed.
The `acquire` and `release` `Effect` values will be run uninterruptibly.
Additionally, the `release` `Effect` value may depend on the `Exit` value
specified when the scope is closed.
acquireRelease(87 const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry((parameter) bucket: Bucket
bucket, (parameter) index: Index
index),88 ((parameter) entry: Entry
entry, (parameter) exit: Exit.Exit<unknown, unknown>
exit) =>89 import Exit
Exit.const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>
Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise.
isFailure((parameter) exit: Exit.Exit<unknown, unknown>
exit) ? const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry((parameter) entry: Entry
entry) : import Effect
Effect.(alias) const void: Effect.Effect<void, never, never>
export void
void90 )91 })92
93const const make: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>
make = import Effect
Effect.const scoped: <Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database | Scope>(effect: Effect.Effect<...>) => Effect.Effect<...>
Scopes all resources used in this workflow to the lifetime of the workflow,
ensuring that their finalizers are run as soon as this workflow completes
execution, whether by success, failure, or interruption.
scoped(94 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Bucket, S3Error, S3 | Scope>> | YieldWrap<Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>> | YieldWrap<...>, Entry>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {95 const const bucket: Bucket
bucket = yield* const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket96 const const index: Index
index = yield* const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex97 return yield* const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry(const bucket: Bucket
bucket, const index: Index
index)98 })99)100
101// The `FailureCaseLiterals` type allows us to provide different error102// scenarios while testing our103//104// For example, by providing the value "S3", we can simulate an error105// scenario specific to the S3 service. This helps us ensure that our106// program handles errors correctly and behaves as expected in various107// situations.108//109// Similarly, we can provide other values like "ElasticSearch" or110// "Database" to simulate error scenarios for those In cases111// where we want to test the absence of errors, we can provide112// `undefined`. By using this parameter, we can thoroughly test our113// services and verify their behavior under different error conditions.114type type FailureCaseLiterals = "S3" | "ElasticSearch" | "Database" | undefined
FailureCaseLiterals = "S3" | "ElasticSearch" | "Database" | undefined115
116class class FailureCase
FailureCase extends import Context
Context.const Tag: <"FailureCase">(id: "FailureCase") => <Self, Shape>() => Context.TagClass<Self, "FailureCase", Shape>
namespace Tag
Tag("FailureCase")<117 class FailureCase
FailureCase,118 type FailureCaseLiterals = "S3" | "ElasticSearch" | "Database" | undefined
FailureCaseLiterals119>() {}120
121// Create a test layer for the S3 service122
123const const S3Test: Layer.Layer<S3, never, FailureCase>
S3Test = import Layer
Layer.const effect: <typeof S3, never, FailureCase>(tag: typeof S3, effect: Effect.Effect<{
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}, never, FailureCase>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(124 class S3
S3,125 import Effect
Effect.const gen: <YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createBucket: Effect.Effect<{
name: string;
}, S3Error, never>;
deleteBucket: (bucket: Bucket) => Effect.Effect<...>;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {126 const const failureCase: FailureCaseLiterals
failureCase = yield* class FailureCase
FailureCase127 return {128 (property) createBucket: Effect.Effect<{
name: string;
}, S3Error, never>
createBucket: import Effect
Effect.const gen: <YieldWrap<Effect.Effect<never, S3Error, never>>, {
name: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, S3Error, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {129 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) globalThis.Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log("[S3] creating bucket")130 if (const failureCase: FailureCaseLiterals
failureCase === "S3") {131 return yield* import Effect
Effect.const fail: <S3Error>(error: S3Error) => Effect.Effect<never, S3Error, never>
Creates an `Effect` that represents a recoverable error.
This `Effect` does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an `Effect`
computation. The failed effect can later be handled with functions like
{@link
catchAll
}
or
{@link
catchTag
}
.
fail(new constructor S3Error(): S3Error
S3Error())132 } else {133 return { (property) name: string
name: "<bucket.name>" }134 }135 }),136 (property) deleteBucket: (bucket: Bucket) => Effect.Effect<void, never, never>
deleteBucket: ((parameter) bucket: Bucket
bucket) =>137 import Console
Console.const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log(`[S3] delete bucket ${(parameter) bucket: Bucket
bucket.(property) Bucket.name: string
name}`)138 }139 })140)141
142// Create a test layer for the ElasticSearch service143
144const const ElasticSearchTest: Layer.Layer<ElasticSearch, never, FailureCase>
ElasticSearchTest = import Layer
Layer.const effect: <typeof ElasticSearch, never, FailureCase>(tag: typeof ElasticSearch, effect: Effect.Effect<{
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}, never, FailureCase>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(145 class ElasticSearch
ElasticSearch,146 import Effect
Effect.const gen: <YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createIndex: Effect.Effect<{
id: string;
}, ElasticSearchError, never>;
deleteIndex: (index: Index) => Effect.Effect<...>;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {147 const const failureCase: FailureCaseLiterals
failureCase = yield* class FailureCase
FailureCase148 return {149 (property) createIndex: Effect.Effect<{
id: string;
}, ElasticSearchError, never>
createIndex: import Effect
Effect.const gen: <YieldWrap<Effect.Effect<never, ElasticSearchError, never>>, {
id: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, ElasticSearchError, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {150 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) globalThis.Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log("[ElasticSearch] creating index")151 if (const failureCase: FailureCaseLiterals
failureCase === "ElasticSearch") {152 return yield* import Effect
Effect.const fail: <ElasticSearchError>(error: ElasticSearchError) => Effect.Effect<never, ElasticSearchError, never>
Creates an `Effect` that represents a recoverable error.
This `Effect` does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an `Effect`
computation. The failed effect can later be handled with functions like
{@link
catchAll
}
or
{@link
catchTag
}
.
fail(new constructor ElasticSearchError(): ElasticSearchError
ElasticSearchError())153 } else {154 return { (property) id: string
id: "<index.id>" }155 }156 }),157 (property) deleteIndex: (index: Index) => Effect.Effect<void, never, never>
deleteIndex: ((parameter) index: Index
index) =>158 import Console
Console.const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log(`[ElasticSearch] delete index ${(parameter) index: Index
index.(property) Index.id: string
id}`)159 }160 })161)162
163// Create a test layer for the Database service164
165const const DatabaseTest: Layer.Layer<Database, never, FailureCase>
DatabaseTest = import Layer
Layer.const effect: <typeof Database, never, FailureCase>(tag: typeof Database, effect: Effect.Effect<{
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}, never, FailureCase>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(166 class Database
Database,167 import Effect
Effect.const gen: <YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<...>;
deleteEntry: (entry: Entry) => Effect.Effect<...>;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {168 const const failureCase: FailureCaseLiterals
failureCase = yield* class FailureCase
FailureCase169 return {170 (property) createEntry: (bucket: Bucket, index: Index) => Effect.Effect<{
id: string;
}, DatabaseError, never>
createEntry: ((parameter) bucket: Bucket
bucket, (parameter) index: Index
index) =>171 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<never, DatabaseError, never>>, {
id: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, DatabaseError, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {172 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) globalThis.Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(173 "[Database] creating entry for bucket" +174 `${(parameter) bucket: Bucket
bucket.(property) Bucket.name: string
name} and index ${(parameter) index: Index
index.(property) Index.id: string
id}`175 )176 if (const failureCase: FailureCaseLiterals
failureCase === "Database") {177 return yield* import Effect
Effect.const fail: <DatabaseError>(error: DatabaseError) => Effect.Effect<never, DatabaseError, never>
Creates an `Effect` that represents a recoverable error.
This `Effect` does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an `Effect`
computation. The failed effect can later be handled with functions like
{@link
catchAll
}
or
{@link
catchTag
}
.
fail(new constructor DatabaseError(): DatabaseError
DatabaseError())178 } else {179 return { (property) id: string
id: "<entry.id>" }180 }181 }),182 (property) deleteEntry: (entry: Entry) => Effect.Effect<void, never, never>
deleteEntry: ((parameter) entry: Entry
entry) =>183 import Console
Console.const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log(`[Database] delete entry ${(parameter) entry: Entry
entry.(property) Entry.id: string
id}`)184 }185 })186)187
188// Merge all the test layers for S3, ElasticSearch, and Database189// services into a single layer190const const layer: Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>
layer = import Layer
Layer.const mergeAll: <[Layer.Layer<S3, never, FailureCase>, Layer.Layer<ElasticSearch, never, FailureCase>, Layer.Layer<Database, never, FailureCase>]>(layers_0: Layer.Layer<...>, layers_1: Layer.Layer<...>, layers_2: Layer.Layer<...>) => Layer.Layer<...>
Combines all the provided layers concurrently, creating a new layer with merged input, error, and output types.
mergeAll(const S3Test: Layer.Layer<S3, never, FailureCase>
S3Test, const ElasticSearchTest: Layer.Layer<ElasticSearch, never, FailureCase>
ElasticSearchTest, const DatabaseTest: Layer.Layer<Database, never, FailureCase>
DatabaseTest)191
192// Create a runnable effect to test the Workspace code. The effect is193// provided with the test layer and a FailureCase service with undefined194// value (no failure case).195const const runnable: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>
runnable = const make: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>
make.(method) Pipeable.pipe<Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>, Effect.Effect<...>, Effect.Effect<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(196 import Effect
Effect.const provide: <S3 | ElasticSearch | Database, never, FailureCase>(layer: Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(const layer: Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>
layer),197 import Effect
Effect.const provideService: <typeof FailureCase>(tag: typeof FailureCase, service: FailureCaseLiterals) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+1 overload)
Provides the effect with the single service it requires. If the effect
requires more than one service use `provide` instead.
provideService(class FailureCase
FailureCase, var undefined
undefined)198)199
200import Effect
Effect.const runPromise: <Either<Entry, S3Error | ElasticSearchError | DatabaseError>, never>(effect: Effect.Effect<Either<Entry, S3Error | ElasticSearchError | DatabaseError>, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(import Effect
Effect.const either: <Entry, S3Error | ElasticSearchError | DatabaseError, never>(self: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>) => Effect.Effect<...>
Returns an effect whose failure and success have been lifted into an
`Either`. The resulting effect cannot fail, because the failure case has
been exposed as part of the `Either` success case.
This method is useful for recovering from effects that may fail.
The error parameter of the returned `Effect` is `never`, since it is
guaranteed the effect does not model failure.
either(const runnable: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>
runnable)).(method) Promise<Either<Entry, S3Error | ElasticSearchError | DatabaseError>>.then<void, never>(onfulfilled?: ((value: Either<Entry, S3Error | ElasticSearchError | DatabaseError>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<...>) | ... 1 more ... | undefined): Promise<...>
Attaches callbacks for the resolution and/or rejection of the Promise.
then(namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) globalThis.Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log)
Let’s examine the test results for the scenario where FailureCase
is set to undefined
(happy path):
[S3] creating bucket[ElasticSearch] creating index[Database] creating entry for bucket <bucket.name> and index <index.id>{ _id: "Either", _tag: "Right", right: { id: "<entry.id>" }}
In this case, all operations succeed, and we see a successful result with right({ id: '<entry.id>' })
.
Now, let’s simulate a failure in the Database
:
const runnable = make.pipe( Effect.provide(layer), Effect.provideService(FailureCase, "Database"))
The console output will be:
[S3] creating bucket[ElasticSearch] creating index[Database] creating entry for bucket <bucket.name> and index <index.id>[ElasticSearch] delete index <index.id>[S3] delete bucket <bucket.name>{ _id: "Either", _tag: "Left", left: { _tag: "DatabaseError" }}
You can observe that once the Database
error occurs, there is a complete rollback that deletes the ElasticSearch
index first and then the associated S3
bucket. The result is a failure with left(new DatabaseError())
.
Let’s now make the index creation fail instead:
const runnable = make.pipe( Effect.provide(layer), Effect.provideService(FailureCase, "ElasticSearch"))
In this case, the console output will be:
[S3] creating bucket[ElasticSearch] creating index[S3] delete bucket <bucket.name>{ _id: "Either", _tag: "Left", left: { _tag: "ElasticSearchError" }}
As expected, once the ElasticSearch
index creation fails, there is a rollback that deletes the S3
bucket. The result is a failure with left(new ElasticSearchError())
.