Queue — Priority, Dedup, Retry
Draft — paired with a runnable example; tip-check before treating as SSOT.
Source: examples/forms/queue/workpool-priority-retry.ts Run: pnpm run example:workpool-retry Hub: Examples → Queue Deep guide: Queues
What this form shows
One WorkPool handle exercising four operators together:
Lanes —
add(normal),prioritize(high),defer(low); each accepts a batch array (one RPC round-trip when remote).Dedup —
key: (job) => job.idskips a second enqueue of the same id while that key is in flight (not a permanent cache — the key frees when the attempt finishes, including before an auto re-enqueue).Retry budget —
attempts: 2means one automatic re-enqueue after failure, thenRetryExhausted. NoonFailurehere → the default disposition (retry until budget, then dead-letter). Per-error routing belongs inonFailureon the Queues guide.Lifecycle — one
eventssubscriber withHyperlink.runForEachTag(pick the tags you care about; ignore the rest). Prefer this over old onExit-style hooks.
Surface is the tip Tag + layer split (contract vs runtime). Bootstrap: start paused: true, wire the subscriber and enqueue, then resume so nothing drains mid-setup.
concurrency: 1 keeps drain order readable for the demo (high → normal → low). Raise it for I/O-bound work; rateLimit is the separate start-rate ceiling (not shown here).
The worker failure is a Schema.TaggedErrorClass on the tags error slot — yieldable and wire-encodable. A bare Schema.String also works for local-only demos; use the schema error class when the failure is part of the public contract.
Expected run
Three jobs. Drain order with concurrency: 1: password-reset (high), welcome (normal), newsletter (low). welcome fails on attempt 1 and succeeds on attempt 2; the others succeed once.
status.completed counts finished attempts (success or failure each increment once) — so expect ≈ 4, then the queue is empty. That is not “unique jobs” and not “successful sends only.” On the tip Tag handle there is no top-level queue.completed; read it from status (same snapshot that carries sizes / inFlight / phase).
The program
import { import CauseCause, import DurationDuration, import EffectEffect, import SchemaSchema } from "effect"
import { import WorkPoolWorkPool, import HyperlinkHyperlink } from "hyperlink-ts"
// ── Contract: payload + typed worker failure ──────────────────────────────────
const const EmailJob: Schema.Struct<{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
}>
const EmailJob: {
Type: Struct.Type<Fields>;
Encoded: Struct.Encoded<Fields>;
DecodingServices: Struct.DecodingServices<Fields>;
EncodingServices: Struct.EncodingServices<Fields>;
Iso: Struct.Iso<Fields>;
fields: Fields;
mapFields: (f: (fields: { readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }) => To, options?: { readonly unsafePreserveChecks?: boolean | undefined } | undefined) => Schema.Struct<{ [K in keyof Readon…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean; }, 'Type'>, readonly []>) => Schema.Struct<{ readonly id: Schema.String…;
annotateKey: (annotations: Schema.Annotations.Key<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }, 'Type'>>) => Schema.Struct<{ readonly id: Schema.String; readonly to: Sc…;
check: (checks_0: Check<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }, 'Type'>>, ...checks: Array<Check<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; re…;
rebuild: (ast: Objects) => Schema.Struct<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }>;
make: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }…;
makeOption: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Option_.Option<Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAtt…;
makeEffect: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Effect.Effect<Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAtte…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
EmailJob = import SchemaSchema.function Struct<
Fields extends Struct.Fields
>(fields: Fields): Struct<Fields>
Defines a struct schema from a map of field schemas.
Details
Each field value is a schema. Use
optionalKey
or
optional
to
mark fields as optional, and
mutableKey
to mark them as mutable.
The resulting schema's Type is a readonly object type with the fields'
decoded types. The Encoded form mirrors the field schemas' encoded types.
Example (Defining a basic struct)
import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
const alice = Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 })
console.log(alice)
// { name: 'Alice', age: 30 }
Struct({
id: Schema.String(property) id: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
id: import SchemaSchema.const String: Stringconst String: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Type-level representation of
String
.
Schema for string values. Validates that the input is typeof "string".
String,
to: Schema.String(property) to: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
to: import SchemaSchema.const String: Stringconst String: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Type-level representation of
String
.
Schema for string values. Validates that the input is typeof "string".
String,
/** Demo flag: fail attempt 1 so the queue schedules a retry. */
failFirstAttempt: Schema.Boolean(property) failFirstAttempt: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<boolean, readonly []>) => Schema.Boolean;
annotateKey: (annotations: Schema.Annotations.Key<boolean>) => Schema.Boolean;
check: (checks_0: Check<boolean>, ...checks: Array<Check<boolean>>) => Schema.Boolean;
rebuild: (ast: Boolean) => Schema.Boolean;
make: (input: boolean, options?: MakeOptions) => boolean;
makeOption: (input: boolean, options?: MakeOptions) => Option_.Option<boolean>;
makeEffect: (input: boolean, options?: MakeOptions) => Effect.Effect<boolean, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Demo flag: fail attempt 1 so the queue schedules a retry.
failFirstAttempt: import SchemaSchema.const Boolean: Booleanconst Boolean: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<boolean, readonly []>) => Schema.Boolean;
annotateKey: (annotations: Schema.Annotations.Key<boolean>) => Schema.Boolean;
check: (checks_0: Check<boolean>, ...checks: Array<Check<boolean>>) => Schema.Boolean;
rebuild: (ast: Boolean) => Schema.Boolean;
make: (input: boolean, options?: MakeOptions) => boolean;
makeOption: (input: boolean, options?: MakeOptions) => Option_.Option<boolean>;
makeEffect: (input: boolean, options?: MakeOptions) => Effect.Effect<boolean, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Type-level representation of
Boolean
.
Schema for boolean values. Validates that the input is typeof "boolean".
When to use
Use to validate values that are already JavaScript booleans.
Boolean,
})
/**
* Wire-ready failure for the tag's `error` slot.
* Prefer `Schema.TaggedErrorClass` (yieldable + encodable) over `Data.TaggedError` when the
* failure is part of the public queue contract.
*/
class class SendErrorclass SendError {
_tag: 'SendError';
id: string;
reason: string;
name: string;
message: string;
stack: string;
cause: unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Wire-ready failure for the tag's error slot.
Prefer Schema.TaggedErrorClass (yieldable + encodable) over Data.TaggedError when the
failure is part of the public queue contract.
SendError extends import SchemaSchema.const TaggedErrorClass: {
<Self = never, Brand = {}>(
identifier?: string
): {
<
Tag extends string,
Fields extends Struct.Fields
>(
tag: Tag,
fields: Fields,
annotations?: Annotations.Declaration<
Self,
readonly [TaggedStruct<Tag, Fields>]
>
): [Self] extends [never]
? MissingSelfGeneric<"Schema.TaggedErrorClass">
: Class<
Self,
TaggedStruct<Tag, Fields>,
Cause_.YieldableError & Brand
>
<
Tag extends string,
S extends Struct<Struct.Fields>
>(
tag: Tag,
schema: S,
annotations?: Annotations.Declaration<
Self,
readonly [
Struct<
Simplify<
{
readonly _tag: tag<Tag>
} & S["fields"]
>
>
]
>
): [Self] extends [never]
? MissingSelfGeneric<"Schema.TaggedErrorClass">
: Class<
Self,
Struct<
Simplify<
{
readonly _tag: tag<Tag>
} & S["fields"]
>
>,
Cause_.YieldableError & Brand
>
}
}
Defines a schema-backed yieldable error class with an automatically populated
_tag field.
When to use
Use to define typed errors that are schema validated, yielded in Effect.gen,
and matched as tagged union members.
Example (Defining a tagged error class)
import { Effect, Schema } from "effect"
class NotFound extends Schema.TaggedErrorClass<NotFound>()("NotFound", {
id: Schema.Number
}) {}
const program = Effect.gen(function*() {
yield* new NotFound({ id: 42 })
})
TaggedErrorClass<class SendErrorclass SendError {
_tag: 'SendError';
id: string;
reason: string;
name: string;
message: string;
stack: string;
cause: unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Wire-ready failure for the tag's error slot.
Prefer Schema.TaggedErrorClass (yieldable + encodable) over Data.TaggedError when the
failure is part of the public queue contract.
SendError>()("SendError", {
id: Schema.String(property) id: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
id: import SchemaSchema.const String: Stringconst String: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Type-level representation of
String
.
Schema for string values. Validates that the input is typeof "string".
String,
reason: Schema.String(property) reason: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
reason: import SchemaSchema.const String: Stringconst String: {
Rebuild: Rebuild;
Iso: Iso;
ast: Ast;
Type: T;
Encoded: E;
DecodingServices: RD;
EncodingServices: RE;
annotate: (annotations: Schema.Annotations.Bottom<string, readonly []>) => Schema.String;
annotateKey: (annotations: Schema.Annotations.Key<string>) => Schema.String;
check: (checks_0: Check<string>, ...checks: Array<Check<string>>) => Schema.String;
rebuild: (ast: String) => Schema.String;
make: (input: string, options?: MakeOptions) => string;
makeOption: (input: string, options?: MakeOptions) => Option_.Option<string>;
makeEffect: (input: string, options?: MakeOptions) => Effect.Effect<string, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Type-level representation of
String
.
Schema for string values. Validates that the input is typeof "string".
String,
}) {}
class class EmailQueueclass EmailQueue {
key: Identifier;
Service: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
};
}
EmailQueue extends import WorkPoolWorkPool.Tag<EmailQueue>(): {
<F, HSelf, D>(key: string, payload: Schema.Struct<F>, options: {
readonly description?: string;
readonly node: NodeKey<HSelf>;
readonly defaults: Hyperlink.DefaultsInput<D>;
}): Hyperlink.TagWithDefaults<QueueNodeBoundTagCarriers<EmailQueue, F, HSelf, Schema.Void, Schema.Never>, D>;
<F, HSelf>(key: string, payload: Schema.Struct<F>, options: {
readonly description?: string;
readonly node: NodeKey<...>;
}): QueueNodeBoundTagCarriers<...>;
<F, Success, Error>(key: string, payload: Schema.Struct<...>, success: Success, error?: Error | undefined): QueueTagCarriers<...>;
<F, D>(key: string, payload: Schema.Struct<...>, options: {
...;
}): Hyperlink.TagWithDefaults<...>;
<F>(key: string, payload: Schema.Struct<...>, options?: {
...;
} | undefined): QueueTagCarriers<...>;
<F, HSelf, D>(key: string, config: WorkPool.QueueTagConfig<...> & {
...;
}): Hyperlink.TagWithDefaults<...>;
<F, HSelf>(key: string, config: WorkPool.QueueTagConfig<...> & {
...;
}): QueueNodeBoundTagCarriers<...>;
<F, D, Success, Error>(key: string, config: WorkPool.QueueTagConfig<...> & {
...;
}): Hyperlink.TagWithDefaults<...>;
<F, Success, Error>(key: string, config: WorkPool.QueueTagConfig<...>): QueueTagCarriers<...>;
}
export Tag
Tag<class EmailQueueclass EmailQueue {
key: Identifier;
Service: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
};
}
EmailQueue>()("examples/EmailQueue", {
QueueTagConfig<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, Void, typeof SendError>.payload: Schema.Struct<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }>(property) QueueTagConfig<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, Void, typeof SendError>.payload: {
Type: Struct.Type<Fields>;
Encoded: Struct.Encoded<Fields>;
DecodingServices: Struct.DecodingServices<Fields>;
EncodingServices: Struct.EncodingServices<Fields>;
Iso: Struct.Iso<Fields>;
fields: Fields;
mapFields: (f: (fields: { readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }) => To, options?: { readonly unsafePreserveChecks?: boolean | undefined } | undefined) => Schema.Struct<{ [K in keyof Readon…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean; }, 'Type'>, readonly []>) => Schema.Struct<{ readonly id: Schema.String…;
annotateKey: (annotations: Schema.Annotations.Key<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }, 'Type'>>) => Schema.Struct<{ readonly id: Schema.String; readonly to: Sc…;
check: (checks_0: Check<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }, 'Type'>>, ...checks: Array<Check<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; re…;
rebuild: (ast: Objects) => Schema.Struct<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }>;
make: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }…;
makeOption: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Option_.Option<Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAtt…;
makeEffect: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Effect.Effect<Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAtte…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
payload: const EmailJob: Schema.Struct<{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
}>
const EmailJob: {
Type: Struct.Type<Fields>;
Encoded: Struct.Encoded<Fields>;
DecodingServices: Struct.DecodingServices<Fields>;
EncodingServices: Struct.EncodingServices<Fields>;
Iso: Struct.Iso<Fields>;
fields: Fields;
mapFields: (f: (fields: { readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }) => To, options?: { readonly unsafePreserveChecks?: boolean | undefined } | undefined) => Schema.Struct<{ [K in keyof Readon…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean; }, 'Type'>, readonly []>) => Schema.Struct<{ readonly id: Schema.String…;
annotateKey: (annotations: Schema.Annotations.Key<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }, 'Type'>>) => Schema.Struct<{ readonly id: Schema.String; readonly to: Sc…;
check: (checks_0: Check<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }, 'Type'>>, ...checks: Array<Check<Schema.Struct.ReadonlySide<{ readonly id: Schema.String; re…;
rebuild: (ast: Objects) => Schema.Struct<{ readonly id: Schema.String; readonly to: Schema.String; readonly failFirstAttempt: Schema.Boolean }>;
make: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }…;
makeOption: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Option_.Option<Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAtt…;
makeEffect: (input: Struct.ReadonlyMakeIn<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean }>, options?: MakeOptions) => Effect.Effect<Struct.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAtte…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
EmailJob,
QueueTagConfig<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, Void, typeof SendError>.error?: typeof SendError | undefined(property) QueueTagConfig<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, Void, typeof SendError>.error?: {
Type: Self;
Encoded: S["Encoded"];
DecodingServices: S["DecodingServices"];
EncodingServices: S["EncodingServices"];
Iso: S["Iso"];
identifier: string;
fields: S["fields"];
mapFields: (f: (fields: { readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }) => To, options?: { readonly unsafePreserveChecks?: boolean | undefined } | undefined) => Schema.Struct<{ [K in keyof Reado…;
extend: (identifier: string) => { (fields: NewFields, annotations?: Schema.Annotations.Declaration<Extended, readonly [Schema.Struct<{ [K in keyof { [K in keyof (('id' | '_tag' | 'reason') & keyof NewFields extends never ? { readonly _tag: Schema.…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<SendError, readonly [Schema.TaggedStruct<'SendError', { readonly id: Schema.String; readonly reason: Schema.String }>]>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.Readonly…;
annotateKey: (annotations: Schema.Annotations.Key<SendError>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }, 'En…;
check: (checks_0: Check<SendError>, ...checks: Array<Check<SendError>>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Sche…;
rebuild: (ast: Declaration) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }, 'Encoded'>, readonly [Schema.Tagg…;
make: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => SendError;
makeOption: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => Option_.Option<SendError>;
makeEffect: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => Effect.Effect<SendError, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
error: class SendErrorclass SendError {
Type: Self;
Encoded: S["Encoded"];
DecodingServices: S["DecodingServices"];
EncodingServices: S["EncodingServices"];
Iso: S["Iso"];
identifier: string;
fields: S["fields"];
mapFields: (f: (fields: { readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }) => To, options?: { readonly unsafePreserveChecks?: boolean | undefined } | undefined) => Schema.Struct<{ [K in keyof Reado…;
extend: (identifier: string) => { (fields: NewFields, annotations?: Schema.Annotations.Declaration<Extended, readonly [Schema.Struct<{ [K in keyof { [K in keyof (('id' | '_tag' | 'reason') & keyof NewFields extends never ? { readonly _tag: Schema.…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<SendError, readonly [Schema.TaggedStruct<'SendError', { readonly id: Schema.String; readonly reason: Schema.String }>]>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.Readonly…;
annotateKey: (annotations: Schema.Annotations.Key<SendError>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }, 'En…;
check: (checks_0: Check<SendError>, ...checks: Array<Check<SendError>>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Sche…;
rebuild: (ast: Declaration) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }, 'Encoded'>, readonly [Schema.Tagg…;
make: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => SendError;
makeOption: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => Option_.Option<SendError>;
makeEffect: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => Effect.Effect<SendError, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Wire-ready failure for the tag's error slot.
Prefer Schema.TaggedErrorClass (yieldable + encodable) over Data.TaggedError when the
failure is part of the public queue contract.
SendError,
}) {}
/** Poll `status.completed` until `expected` finished attempts (success or failure each count once). */
const const waitUntilCompleted: (
expected: number
) => Effect.Effect<number, never, EmailQueue>
Poll status.completed until expected finished attempts (success or failure each count once).
waitUntilCompleted = (expected: numberexpected: number) =>
import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue = yield* class EmailQueueclass EmailQueue {
key: Identifier;
Service: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
};
description: string | undefined;
of: (this: void, self: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>;
context: (self: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => Context<EmailQueue>;
use: (f: (service: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, EmailQueue | R>;
useSync: (f: (service: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => A) => Effect.Effect<A, never, EmailQueue>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
EmailQueue
while (true) {
const { const completed: numbercompleted } = yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.status: Hyperlink.Subscribable<QueueStatus>(property) WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.status: {
get: Effect.Effect<A>;
changes: Stream.Stream<A>;
}
Live current-state snapshot (per-priority sizes, paused, in-flight, completed, phase).
status.Subscribable<QueueStatus>.get: Effect.Effect<A>(property) Subscribable<QueueStatus>.get: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
get
if (const completed: numbercompleted >= expected: numberexpected) return const completed: numbercompleted
yield* import EffectEffect.const sleep: (
duration: Duration.Input
) => Effect<void>
Returns an effect that suspends the current fiber for the specified duration
without blocking a JavaScript thread.
Example (Pausing without blocking)
import { Console, Effect } from "effect"
const program = Effect.gen(function*() {
yield* Console.log("Start")
yield* Effect.sleep("2 seconds")
yield* Console.log("End")
})
Effect.runFork(program)
// Output: "Start" (immediately)
// Output: "End" (after 2 seconds)
sleep(import DurationDuration.const millis: (millis: number) => DurationCreates a Duration from milliseconds.
Example (Creating durations from milliseconds)
import { Duration } from "effect"
const duration = Duration.millis(1000)
console.log(Duration.toMillis(duration)) // 1000
millis(10))
}
})
// ── Layer: worker + policy (Tag stays free of runtime config) ─────────────────
const const EmailQueueLive: Layer<
| Storage
| EmailQueue
| Hyperlink.Local<EmailQueue>,
never,
never
>
const EmailQueueLive: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Storage | EmailQueue | Local<EmailQueue>>, never, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
EmailQueueLive = import WorkPoolWorkPool.function layer<EmailQueue, {
readonly id: Schema.String;
readonly to: Schema.String;
readonly failFirstAttempt: Schema.Boolean;
}, never, never, Schema.Void, typeof SendError>(tag: QueueTagFor<EmailQueue, {
readonly id: Schema.String;
readonly to: Schema.String;
readonly failFirstAttempt: Schema.Boolean;
}, Schema.Void, typeof SendError>, config: QueueVerbConfig<{
readonly id: Schema.String;
readonly to: Schema.String;
readonly failFirstAttempt: Schema.Boolean;
}, SendError, never, never, Schema.Void>): Layer<...> (+1 overload)
Run this WorkPool locally — soft-defaults
Store.Storage
(R fulfilled; override by
providing an app store into this layer). Accepts a plain
Tag
or a
priority
tag and
dispatches to the matching engine.
layerMemory
is an alias for the same soft-default.
layer(class EmailQueueclass EmailQueue {
key: Identifier;
Service: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
};
description: string | undefined;
of: (this: void, self: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>;
context: (self: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => Context<EmailQueue>;
use: (f: (service: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, EmailQueue | R>;
useSync: (f: (service: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => A) => Effect.Effect<A, never, EmailQueue>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
EmailQueue, {
paused?: boolean | undefinedStart with processing paused. Call resume to begin.
paused: true, // enqueue / subscribe first; drain only after `resume`
concurrency?: number | undefinedMax items processing concurrently (worker count).
concurrency: 1, // sequential — log order stays readable for the demo
capacity?: number | undefinedMax items per priority queue (bounded backpressure).
capacity: 100,
key?: | ((
item: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
) => string)
| undefined
Extract a deduplication key from each item. When set, items with a key
already in-flight (enqueued or processing) are silently dropped.
The key is released after the worker effect completes.
key: (job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job) => job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job.id: stringid, // same id while in flight → skipped (not a permanent cache)
attempts?: number | undefinedMax attempts for an item — the initial try plus automatic re-enqueues. On failure the
worker re-enqueues the item at its own priority, preserving its attempt count, until
attempts is reached; then it's exhausted (emits a RetryExhausted event). Observe the
RetryScheduled / RetryExhausted lifecycle on the
QueueHandleApi.events
stream.
In-place retry of the worker effect is a separate concern — put Effect.retry(...) on your
effect.
attempts: 2, // initial try + one automatic re-enqueue; then RetryExhausted
// No `onFailure` → default disposition: retry until `attempts`, then dead-letter.
effect: (
item: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>,
ctx: WorkPool.EffectContext<
Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>,
QueueEnqueueErrors,
never
>
) => Effect.Effect<void, SendError, never>
Daemon each item. The success channel A is driven by the tag's success wire schema
(default void): with a success schema the worker must return Effect<A, E, R> and that
value rides Completed.success / store.completed; without one it stays Effect<void, E, R>.
effect: (job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job, ctx: WorkPool.EffectContext<
Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>,
QueueEnqueueErrors,
never
>
(parameter) ctx: {
add: QueueEnqueue<T, EEnqueue, R>;
prioritize: QueueEnqueue<T, EEnqueue, R>;
defer: QueueEnqueue<T, EEnqueue, R>;
attempts: number;
enqueuedAt: number;
priority: Priority;
}
ctx) =>
import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
yield* import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(
`send attempt ${var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(ctx: WorkPool.EffectContext<
Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>,
QueueEnqueueErrors,
never
>
(parameter) ctx: {
add: QueueEnqueue<T, EEnqueue, R>;
prioritize: QueueEnqueue<T, EEnqueue, R>;
defer: QueueEnqueue<T, EEnqueue, R>;
attempts: number;
enqueuedAt: number;
priority: Priority;
}
ctx.EffectContext<Struct<Fields extends Struct.Fields>.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, "Type">, QueueEnqueueErrors, never>.attempts: numberHow many times this item has been processed (1 = first attempt).
attempts)} for ${job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job.id: stringid} (${ctx: WorkPool.EffectContext<
Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>,
QueueEnqueueErrors,
never
>
(parameter) ctx: {
add: QueueEnqueue<T, EEnqueue, R>;
prioritize: QueueEnqueue<T, EEnqueue, R>;
defer: QueueEnqueue<T, EEnqueue, R>;
attempts: number;
enqueuedAt: number;
priority: Priority;
}
ctx.EffectContext<Struct<Fields extends Struct.Fields>.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, "Type">, QueueEnqueueErrors, never>.priority: PriorityThe priority level this item was enqueued at.
priority})`,
)
if (job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job.failFirstAttempt: booleanDemo flag: fail attempt 1 so the queue schedules a retry.
failFirstAttempt && ctx: WorkPool.EffectContext<
Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>,
QueueEnqueueErrors,
never
>
(parameter) ctx: {
add: QueueEnqueue<T, EEnqueue, R>;
prioritize: QueueEnqueue<T, EEnqueue, R>;
defer: QueueEnqueue<T, EEnqueue, R>;
attempts: number;
enqueuedAt: number;
priority: Priority;
}
ctx.EffectContext<Struct<Fields extends Struct.Fields>.ReadonlySide<{ readonly id: String; readonly to: String; readonly failFirstAttempt: Boolean; }, "Type">, QueueEnqueueErrors, never>.attempts: numberHow many times this item has been processed (1 = first attempt).
attempts === 1) {
return yield* new constructor SendError(props: {
readonly id: string;
readonly reason: string;
readonly _tag?: "SendError" | undefined;
}, options?: Schema.MakeOptions | undefined): SendError
constructor SendError(props: {
readonly id: string;
readonly reason: string;
readonly _tag?: "SendError" | undefined;
}, options?: Schema.MakeOptions | undefined): {
Type: Self;
Encoded: S["Encoded"];
DecodingServices: S["DecodingServices"];
EncodingServices: S["EncodingServices"];
Iso: S["Iso"];
identifier: string;
fields: S["fields"];
mapFields: (f: (fields: { readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }) => To, options?: { readonly unsafePreserveChecks?: boolean | undefined } | undefined) => Schema.Struct<{ [K in keyof Reado…;
extend: (identifier: string) => { (fields: NewFields, annotations?: Schema.Annotations.Declaration<Extended, readonly [Schema.Struct<{ [K in keyof { [K in keyof (('id' | '_tag' | 'reason') & keyof NewFields extends never ? { readonly _tag: Schema.…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<SendError, readonly [Schema.TaggedStruct<'SendError', { readonly id: Schema.String; readonly reason: Schema.String }>]>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.Readonly…;
annotateKey: (annotations: Schema.Annotations.Key<SendError>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }, 'En…;
check: (checks_0: Check<SendError>, ...checks: Array<Check<SendError>>) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Sche…;
rebuild: (ast: Declaration) => Schema.decodeTo<Schema.declareConstructor<SendError, Schema.Struct.ReadonlySide<{ readonly _tag: Schema.tag<'SendError'>; readonly id: Schema.String; readonly reason: Schema.String }, 'Encoded'>, readonly [Schema.Tagg…;
make: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => SendError;
makeOption: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => Option_.Option<SendError>;
makeEffect: (input: { readonly id: string; readonly reason: string; readonly _tag?: 'SendError' | undefined }, options?: MakeOptions) => Effect.Effect<SendError, SchemaError, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Wire-ready failure for the tag's error slot.
Prefer Schema.TaggedErrorClass (yieldable + encodable) over Data.TaggedError when the
failure is part of the public queue contract.
SendError({
id: stringid: job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job.id: stringid,
reason: stringreason: "simulated transient SMTP failure",
})
}
yield* import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(`sent:${job: Schema.Struct.ReadonlySide<
{
readonly id: Schema.String
readonly to: Schema.String
readonly failFirstAttempt: Schema.Boolean
},
"Type"
>
(parameter) job: {
id: string;
to: string;
failFirstAttempt: boolean;
}
job.id: stringid}`)
}),
})
// ── Drive: observe → enqueue → resume → wait ──────────────────────────────────
const const program: Effect.Effect<
void,
never,
Scope | EmailQueue
>
const program: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
program = import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue = yield* class EmailQueueclass EmailQueue {
key: Identifier;
Service: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
};
description: string | undefined;
of: (this: void, self: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>;
context: (self: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => Context<EmailQueue>;
use: (f: (service: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, EmailQueue | R>;
useSync: (f: (service: WorkPool.WorkPool<{ id: string; to: string; failFirstAttempt: boolean }, void, SendError, never>) => A) => Effect.Effect<A, never, EmailQueue>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
EmailQueue
// Fork one subscriber before resume so early Enqueued / Started events aren't missed.
yield* import EffectEffect.const forkScoped: <
Arg extends
| Effect<any, any, any>
| {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
| undefined = {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
>(
effectOrOptions?: Arg,
options?:
| {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
| undefined
) => [Arg] extends [
Effect<infer _A, infer _E, infer _R>
]
? Effect<Fiber<_A, _E>, never, _R | Scope>
: <A, E, R>(
self: Effect<A, E, R>
) => Effect<Fiber<A, E>, never, R | Scope>
Forks the fiber in a Scope, interrupting it when the scope is closed.
Example (Forking into the current scope)
import { Effect } from "effect"
const backgroundTask = Effect.gen(function*() {
yield* Effect.sleep("5 seconds")
yield* Effect.log("Background task completed")
return "result"
})
const program = Effect.scoped(
Effect.gen(function*() {
const fiber = yield* backgroundTask.pipe(Effect.forkScoped)
// or fork a fiber that starts immediately:
yield* backgroundTask.pipe(Effect.forkScoped({ startImmediately: true }))
yield* Effect.log("Task forked in scope")
yield* Effect.sleep("1 second")
// Fiber will be interrupted when scope closes
return "scope completed"
})
)
forkScoped(
const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.events: Stream.Stream<QueueEvent<Payload, Error, Success>>(property) WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.events: {
channel: Channel.Channel<Arr.NonEmptyReadonlyArray<A>, E, void, unknown, unknown, unknown, R>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
Discrete entry / worker / queue lifecycle events.
events.Pipeable.pipe<Stream<WorkPool.QueueEvent<{
id: string;
to: string;
failFirstAttempt: boolean;
}, SendError, void>, never, never>, Effect.Effect<void, never, never>>(this: Stream<WorkPool.QueueEvent<{
id: string;
to: string;
failFirstAttempt: boolean;
}, SendError, void>, never, never>, ab: (_: Stream<WorkPool.QueueEvent<{
id: string;
to: string;
failFirstAttempt: boolean;
}, SendError, void>, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe(
import HyperlinkHyperlink.const runForEachTag: {
<
A extends TaggedEvent,
Cases extends TagHandlers<A, unknown, unknown>
>(
handlers: Cases
): (
self: Stream.Stream<A>
) => Effect.Effect<
void,
HandlersError<Cases>,
HandlersContext<Cases>
>
<
A extends TaggedEvent,
K extends A["_tag"],
E,
R
>(
tag: K,
f: (
event: Extract<A, { readonly _tag: K }>
) => Effect.Effect<void, E, R>
): (
self: Stream.Stream<A>
) => Effect.Effect<void, E, R>
<
A extends TaggedEvent,
K extends A["_tag"],
E,
R
>(
self: Stream.Stream<A>,
tag: K,
f: (
event: Extract<A, { readonly _tag: K }>
) => Effect.Effect<void, E, R>
): Effect.Effect<void, E, R>
<
A extends TaggedEvent,
Cases extends TagHandlers<A, unknown, unknown>
>(
self: Stream.Stream<A>,
handlers: Cases
): Effect.Effect<
void,
HandlersError<Cases>,
HandlersContext<Cases>
>
}
runForEachTag({
type Enqueued: (e: {
readonly _tag: "Enqueued"
readonly entries: readonly WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>[]
readonly priority: WorkPool.Priority
readonly batchId?: string
}) => Effect.Effect<void, never, never>
Enqueued: (e: {
readonly _tag: "Enqueued"
readonly entries: ReadonlyArray<
QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
>
readonly priority: Priority
readonly batchId?: string
}
e) =>
import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(`enqueued ${var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(e: {
readonly _tag: "Enqueued"
readonly entries: ReadonlyArray<
QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
>
readonly priority: Priority
readonly batchId?: string
}
e.entries: ReadonlyArray<QueueEntry<T>>entries.ReadonlyArray<T>.length: numberGets the length of the array. This is a number one higher than the highest element defined in an array.
length)} ${e: {
readonly _tag: "Enqueued"
readonly entries: ReadonlyArray<
QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
>
readonly priority: Priority
readonly batchId?: string
}
e.priority: Prioritypriority} job(s)`),
type Completed: (e: {
readonly _tag: "Completed"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly success: void
readonly elapsed: Duration.Duration
}) => Effect.Effect<void, never, never>
Completed: (e: {
readonly _tag: "Completed"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly success: void
readonly elapsed: Duration.Duration
}
e) =>
import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(
`sent ${e: {
readonly _tag: "Completed"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly success: void
readonly elapsed: Duration.Duration
}
e.entry: QueueEntry<T>(property) entry: {
item: T;
entryId: string;
key: string;
priority: Priority;
lane: number;
attempts: number;
timestamps: QueueEntryTimestamps;
batchId: string;
releaseId: string;
sourceHyperlinkId: string;
attributes: { readonly [key: string]: unknown };
}
entry.QueueEntry<{ id: string; to: string; failFirstAttempt: boolean; }>.item: {
id: string;
to: string;
failFirstAttempt: boolean;
}
item.id: stringid} after ${var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(e: {
readonly _tag: "Completed"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly success: void
readonly elapsed: Duration.Duration
}
e.entry: QueueEntry<T>(property) entry: {
item: T;
entryId: string;
key: string;
priority: Priority;
lane: number;
attempts: number;
timestamps: QueueEntryTimestamps;
batchId: string;
releaseId: string;
sourceHyperlinkId: string;
attributes: { readonly [key: string]: unknown };
}
entry.QueueEntry<{ id: string; to: string; failFirstAttempt: boolean; }>.attempts: numberattempts)} attempt(s)`,
),
type RetryScheduled: (e: {
readonly _tag: "RetryScheduled"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
readonly nextAttempt: number
}) => Effect.Effect<void, never, never>
RetryScheduled: (e: {
readonly _tag: "RetryScheduled"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
readonly nextAttempt: number
}
e) =>
import EffectEffect.const logWarning: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the WARNING level.
Example (Logging warnings)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logWarning("API rate limit approaching")
yield* Effect.logWarning("Retries remaining:", 2, "Operation:", "fetchData")
// Useful for non-critical issues
const deprecated = true
if (deprecated) {
yield* Effect.logWarning("Using deprecated API endpoint")
}
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=WARN message="API rate limit approaching"
// timestamp=2023-... level=WARN message="Retries remaining: 2 Operation: fetchData"
// timestamp=2023-... level=WARN message="Using deprecated API endpoint"
logWarning(`retry ${e: {
readonly _tag: "RetryScheduled"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
readonly nextAttempt: number
}
e.entry: QueueEntry<T>(property) entry: {
item: T;
entryId: string;
key: string;
priority: Priority;
lane: number;
attempts: number;
timestamps: QueueEntryTimestamps;
batchId: string;
releaseId: string;
sourceHyperlinkId: string;
attributes: { readonly [key: string]: unknown };
}
entry.QueueEntry<{ id: string; to: string; failFirstAttempt: boolean; }>.item: {
id: string;
to: string;
failFirstAttempt: boolean;
}
item.id: stringid}: ${import CauseCause.const pretty: <E>(
cause: Cause<E>
) => string
Formats a Cause as a human-readable string for logging or debugging.
When to use
Use to render a whole cause as one human-readable string for logs or
diagnostics.
Details
Delegates to
prettyErrors
to convert each reason to an Error,
then joins their stack traces with newlines. Nested Error.cause chains
are rendered inline with indentation:
ErrorName: message
at ...
at ... {
[cause]: NestedError: message
at ...
}
Span annotations are appended to the relevant stack frames when available.
Gotchas
Rendering an empty cause produces an empty string because there are no
errors to render.
Example (Rendering a cause)
import { Cause } from "effect"
const rendered = Cause.pretty(Cause.fail("something went wrong"))
console.log(rendered.includes("something went wrong")) // true
pretty(e: {
readonly _tag: "RetryScheduled"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
readonly nextAttempt: number
}
e.cause: Cause.Cause<E>(property) cause: {
reasons: ReadonlyArray<Reason<E>>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
cause)}`),
type RetryExhausted: (e: {
readonly _tag: "RetryExhausted"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
}) => Effect.Effect<void, never, never>
RetryExhausted: (e: {
readonly _tag: "RetryExhausted"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
}
e) =>
import EffectEffect.const logError: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the ERROR level.
Example (Logging errors)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logError("Database connection failed")
yield* Effect.logError(
"Error code:",
500,
"Message:",
"Internal server error"
)
// Can be used with error objects
const error = new Error("Something went wrong")
yield* Effect.logError("Caught error:", error.message)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=ERROR message="Database connection failed"
// timestamp=2023-... level=ERROR message="Error code: 500 Message: Internal server error"
// timestamp=2023-... level=ERROR message="Caught error: Something went wrong"
logError(`dead-letter ${e: {
readonly _tag: "RetryExhausted"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
}
e.entry: QueueEntry<T>(property) entry: {
item: T;
entryId: string;
key: string;
priority: Priority;
lane: number;
attempts: number;
timestamps: QueueEntryTimestamps;
batchId: string;
releaseId: string;
sourceHyperlinkId: string;
attributes: { readonly [key: string]: unknown };
}
entry.QueueEntry<{ id: string; to: string; failFirstAttempt: boolean; }>.item: {
id: string;
to: string;
failFirstAttempt: boolean;
}
item.id: stringid}: ${import CauseCause.const pretty: <E>(
cause: Cause<E>
) => string
Formats a Cause as a human-readable string for logging or debugging.
When to use
Use to render a whole cause as one human-readable string for logs or
diagnostics.
Details
Delegates to
prettyErrors
to convert each reason to an Error,
then joins their stack traces with newlines. Nested Error.cause chains
are rendered inline with indentation:
ErrorName: message
at ...
at ... {
[cause]: NestedError: message
at ...
}
Span annotations are appended to the relevant stack frames when available.
Gotchas
Rendering an empty cause produces an empty string because there are no
errors to render.
Example (Rendering a cause)
import { Cause } from "effect"
const rendered = Cause.pretty(Cause.fail("something went wrong"))
console.log(rendered.includes("something went wrong")) // true
pretty(e: {
readonly _tag: "RetryExhausted"
readonly entry: WorkPool.QueueEntry<{
id: string
to: string
failFirstAttempt: boolean
}>
readonly cause: Cause.Cause<SendError>
}
e.cause: Cause.Cause<E>(property) cause: {
reasons: ReadonlyArray<Reason<E>>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
cause)}`),
}),
),
)
// Lanes while paused: high → normal → low. With concurrency 1, drain order matches.
yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.add: QueueEnqueue<Payload, never, Requirements>add([
{ id: stringid: "welcome", to: stringto: "[email protected]", failFirstAttempt: booleanDemo flag: fail attempt 1 so the queue schedules a retry.
failFirstAttempt: true },
])
yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.defer: QueueEnqueue<Payload, never, Requirements>defer([
{ id: stringid: "newsletter", to: stringto: "[email protected]", failFirstAttempt: booleanDemo flag: fail attempt 1 so the queue schedules a retry.
failFirstAttempt: false },
])
yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.prioritize: QueueEnqueue<Payload, never, Requirements>prioritize([
{ id: stringid: "password-reset", to: stringto: "[email protected]", failFirstAttempt: booleanDemo flag: fail attempt 1 so the queue schedules a retry.
failFirstAttempt: false },
])
const const pending: numberpending = yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.size: Hyperlink.Subscribable<number>(property) WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.size: {
get: Effect.Effect<A>;
changes: Stream.Stream<A>;
}
Total pending items across all priority lanes.
size.Subscribable<number>.get: Effect.Effect<A>(property) Subscribable<number>.get: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
get
yield* import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(`pending before resume: ${var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const pending: numberpending)}`)
yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.resume: Effect.Effect<void>(property) WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.resume: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Resume processing after a pause.
resume
// welcome: fail + succeed (2) + two other jobs once each → 4 finished attempts.
const const completed: numbercompleted = yield* const waitUntilCompleted: (
expected: number
) => Effect.Effect<number, never, EmailQueue>
Poll status.completed until expected finished attempts (success or failure each count once).
waitUntilCompleted(4)
yield* import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(`completed item attempts: ${var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const completed: numbercompleted)}`)
const const empty: booleanempty = yield* const queue: WorkPool.WorkPool<
{
id: string
to: string
failFirstAttempt: boolean
},
void,
SendError,
never
>
const queue: {
status: Hyperlink.Subscribable<QueueStatus>;
size: Hyperlink.Subscribable<number>;
isEmpty: Hyperlink.Subscribable<boolean>;
start: Effect.Effect<void, never, Requirements>;
pause: Effect.Effect<void>;
resume: Effect.Effect<void>;
shutdown: Effect.Effect<void>;
clear: Effect.Effect<number, never, Requirements>;
metrics: { readonly stream: Stream.Stream<QueueMetrics>; readonly query: (input: { readonly limit?: number; readonly since?: DateTime.Utc; readonly until?: DateTime.Utc }) => Effect.Effect<ReadonlyArray<QueueMetrics>, never, Requirements> };
add: QueueEnqueue<Payload, never, Requirements>;
prioritize: QueueEnqueue<Payload, never, Requirements>;
defer: QueueEnqueue<Payload, never, Requirements>;
enqueue: (entries: ReadonlyArray<QueueEntry<Payload>>) => Effect.Effect<void, never, Requirements>;
release: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
releaseEncoded: (input: { readonly options?: QueueReleaseOptions }) => Effect.Effect<ReadonlyArray<Hyperlink.Decoded<typeof queueEncodedEntry>>, QueueReleaseEncodingError, Requirements>;
deadLetter: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
drop: (input: { readonly selector: QueueEntrySelector<Payload> | QueueEntry<Payload>; readonly options: QueueRouteOptions }) => Effect.Effect<ReadonlyArray<QueueEntry<Payload>>, never, Requirements>;
events: Stream.Stream<QueueEvent<Payload, Error, Success>>;
}
queue.WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.isEmpty: Hyperlink.Subscribable<boolean>(property) WorkPool<{ id: string; to: string; failFirstAttempt: boolean; }, void, SendError, never>.isEmpty: {
get: Effect.Effect<A>;
changes: Stream.Stream<A>;
}
Whether all priority queues are empty.
isEmpty.Subscribable<boolean>.get: Effect.Effect<A>(property) Subscribable<boolean>.get: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
get
yield* import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo(`queue empty: ${var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const empty: booleanempty)}`)
})
void import EffectEffect.const runPromise: <A, E>(
effect: Effect<A, E>,
options?: RunOptions | undefined
) => Promise<A>
Executes an effect and returns the result as a Promise.
When to use
Use when you need to execute an effect and work with the
result using Promise syntax, typically for compatibility with other
promise-based code.
If the effect succeeds, the promise will resolve with the result. If the
effect fails, the promise will reject with an error.
Example (Running a successful effect as a Promise)
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1
Example (Running effects as promises)
//Example: Handling a Failing Effect as a Rejected Promise
import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)
// Output:
// (FiberFailure) Error: my error
runPromise(
const program: Effect.Effect<
void,
never,
Scope | EmailQueue
>
const program: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
program.Pipeable.pipe<Effect.Effect<void, never, EmailQueue | Scope>, Effect.Effect<void, never, Scope>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, EmailQueue | Scope>) => Effect.Effect<void, never, Scope>, bc: (_: Effect.Effect<void, never, Scope>) => Effect.Effect<void, never, never>, cd: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)pipe(
import EffectEffect.const provide: {
<
Layers extends [
Layer.Any,
...Array<Layer.Any>
]
>(
layers: Layers,
options?:
| { readonly local?: boolean | undefined }
| undefined
): <A, E, R>(
self: Effect<A, E, R>
) => Effect<
A,
E | Layer.Error<Layers[number]>,
| Layer.Services<Layers[number]>
| Exclude<R, Layer.Success<Layers[number]>>
>
<ROut, E2, RIn>(
layer: Layer.Layer<ROut, E2, RIn>,
options?:
| { readonly local?: boolean | undefined }
| undefined
): <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E | E2, RIn | Exclude<R, ROut>>
<R2>(context: Context.Context<R2>): <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E, Exclude<R, R2>>
<
A,
E,
R,
Layers extends [
Layer.Any,
...Array<Layer.Any>
]
>(
self: Effect<A, E, R>,
layers: Layers,
options?:
| { readonly local?: boolean | undefined }
| undefined
): Effect<
A,
E | Layer.Error<Layers[number]>,
| Layer.Services<Layers[number]>
| Exclude<R, Layer.Success<Layers[number]>>
>
<A, E, R, ROut, E2, RIn>(
self: Effect<A, E, R>,
layer: Layer.Layer<ROut, E2, RIn>,
options?:
| { readonly local?: boolean | undefined }
| undefined
): Effect<A, E | E2, RIn | Exclude<R, ROut>>
<A, E, R, R2>(
self: Effect<A, E, R>,
context: Context.Context<R2>
): Effect<A, E, Exclude<R, R2>>
}
Provides dependencies to an effect using layers or a context. Use options.local
to build the layer every time; by default, layers are shared between provide
calls.
Example (Providing dependencies with a layer)
import { Context, Effect, Layer } from "effect"
interface Database {
readonly query: (sql: string) => Effect.Effect<string>
}
const Database = Context.Service<Database>("Database")
const DatabaseLive = Layer.succeed(Database)({
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result for: ${sql}`))
})
const program = Effect.gen(function*() {
const db = yield* Database
return yield* db.query("SELECT * FROM users")
})
const provided = Effect.provide(program, DatabaseLive)
Effect.runPromise(provided).then(console.log)
// Output: "Result for: SELECT * FROM users"
provide(const EmailQueueLive: Layer<
| Storage
| EmailQueue
| Hyperlink.Local<EmailQueue>,
never,
never
>
const EmailQueueLive: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Storage | EmailQueue | Local<EmailQueue>>, never, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
EmailQueueLive),
import EffectEffect.const scoped: <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E, Exclude<R, Scope>>
Runs an effect with a scope that closes when the effect completes.
When to use
Use to acquire scoped resources for the duration of a single workflow.
Details
Finalizers for resources acquired inside the workflow run as soon as the
workflow completes, whether by success, failure, or interruption.
Example (Running a scoped acquisition)
import { Console, Effect } from "effect"
const resource = Effect.acquireRelease(
Console.log("Acquiring resource").pipe(Effect.as("resource")),
() => Console.log("Releasing resource")
)
const program = Effect.scoped(
Effect.gen(function*() {
const res = yield* resource
yield* Console.log(`Using ${res}`)
return res
})
)
Effect.runFork(program)
// Output: "Acquiring resource"
// Output: "Using resource"
// Output: "Releasing resource"
scoped,
import EffectEffect.const tap: {
<A, B, E2, R2>(
f: (a: NoInfer<A>) => Effect<B, E2, R2>
): <E, R>(
self: Effect<A, E, R>
) => Effect<A, E | E2, R | R2>
<B, E2, R2>(f: Effect<B, E2, R2>): <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E | E2, R | R2>
<A, E, R, B, E2, R2>(
self: Effect<A, E, R>,
f: (a: NoInfer<A>) => Effect<B, E2, R2>
): Effect<A, E | E2, R | R2>
<A, E, R, B, E2, R2>(
self: Effect<A, E, R>,
f: Effect<B, E2, R2>
): Effect<A, E | E2, R | R2>
}
Runs a side effect with the result of an effect without changing the original
value.
When to use
Use when you need to run an effectful observation, such as logging or
tracking, while passing the original success value to the next step.
Details
tap works similarly to flatMap, but it ignores the result of the function
passed to it. The value from the previous effect remains available for the
next part of the chain. Note that if the side effect fails, the entire chain
will fail too.
Example (Logging a step in a pipeline)
import { Console, Data, Effect, pipe } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
// Log the fetched transaction amount
Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)),
// `amount` is still available!
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(finalAmount).then(console.log)
// Output:
// Apply a discount to: 100
// 95
tap(() => import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo("form:queue-hyperlink-priority-retry finished OK")),
),
)