Layer.Layer<
HttpPlatform | Etag.Generator | NodeServices | HttpServer,
ServeError,
ShardingConfig.ShardingConfig
>Provides the HTTP server and Node HTTP services used by cluster runners,
listening on ShardingConfig.runnerListenAddress or runnerAddress.
export const const layerHttpServer: Layer.Layer<
| HttpPlatform
| Etag.Generator
| NodeServices
| HttpServer,
ServeError,
ShardingConfig.ShardingConfig
>
const layerHttpServer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<HttpServer | Generator | HttpPlatform | NodeServices>, ServeError, ShardingConfig>;
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; <…;
}
Provides the HTTP server and Node HTTP services used by cluster runners,
listening on ShardingConfig.runnerListenAddress or runnerAddress.
layerHttpServer: import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<
| class HttpPlatformclass HttpPlatform {
key: Identifier;
Service: {
fileResponse: (path: string, options?: Response.Options.WithContent & { readonly bytesToRead?: FileSystem.SizeInput | undefined; readonly chunkSize?: FileSystem.SizeInput | undefined; readonly offset?: FileSystem.SizeInput | undefined }) => Effect.Effec…;
fileWebResponse: (file: Body.HttpBody.FileLike, options?: Response.Options.WithContent & { readonly bytesToRead?: FileSystem.SizeInput | undefined; readonly chunkSize?: FileSystem.SizeInput | undefined; readonly offset?: FileSystem.SizeInput | undefined })…;
};
}
Service for platform-specific HTTP response helpers, including file-backed server responses.
HttpPlatform
| import EtagEtag.class Generatorclass Generator {
key: Identifier;
Service: {
fromFileInfo: (info: FileSystem.File.Info) => Effect.Effect<Etag>;
fromFileWeb: (file: Body.HttpBody.FileLike) => Effect.Effect<Etag>;
};
}
Service for generating ETags from filesystem file information or Web File-like metadata.
Generator
| type NodeServices = ChildProcessSpawner | Crypto | FileSystem | Path | Stdio | TerminalThe union of core services provided by the Node platform layer, including
child process spawning, filesystem, path, stdio, and terminal services.
NodeServices
| class HttpServerclass HttpServer {
key: Identifier;
Service: {
serve: { <E, R>(effect: Effect.Effect<HttpServerResponse, E, R>): Effect.Effect<void, never, Exclude<R, HttpServerRequest> | Scope.Scope>; <E, R, App extends Effect.Effect<HttpServerResponse, any, any>>(effect: Effect.Effect<HttpServerResponse, E…;
address: Address;
};
}
Service tag for an HTTP server runtime.
Details
The service can serve an HTTP response effect and exposes the address where the
server is listening.
HttpServer,
class ServeErrorclass ServeError {
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;
_tag: Tag;
}
Error wrapping a low-level failure from the HTTP server implementation.
ServeError,
import ShardingConfigShardingConfig.class ShardingConfigclass ShardingConfig {
key: Identifier;
Service: {
runnerAddress: Option.Option<RunnerAddress>;
runnerListenAddress: Option.Option<RunnerAddress>;
runnerShardWeight: number;
availableShardGroups: ReadonlyArray<string>;
assignedShardGroups: ReadonlyArray<string>;
shardsPerGroup: number;
shardLockRefreshInterval: Duration.Input;
shardLockExpiration: Duration.Input;
shardLockDisableAdvisory: boolean;
preemptiveShutdown: boolean;
entityMailboxCapacity: number | "unbounded";
entityMaxIdleTime: Duration.Input;
entityRegistrationTimeout: Duration.Input;
entityTerminationTimeout: Duration.Input;
entityMessagePollInterval: Duration.Input;
entityReplyPollInterval: Duration.Input;
refreshAssignmentsInterval: Duration.Input;
sendRetryInterval: Duration.Input;
runnerHealthCheckInterval: Duration.Input;
simulateRemoteSerialization: boolean;
};
}
Represents the configuration for the Sharding service on a given runner.
ShardingConfig
> = 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 config: {
readonly runnerAddress: Option.Option<RunnerAddress>
readonly runnerListenAddress: Option.Option<RunnerAddress>
readonly runnerShardWeight: number
readonly availableShardGroups: ReadonlyArray<string>
readonly assignedShardGroups: ReadonlyArray<string>
readonly shardsPerGroup: number
readonly shardLockRefreshInterval: Duration.Input
readonly shardLockExpiration: Duration.Input
readonly shardLockDisableAdvisory: boolean
readonly preemptiveShutdown: boolean
readonly entityMailboxCapacity:
| number
| "unbounded"
readonly entityMaxIdleTime: Duration.Input
readonly entityRegistrationTimeout: Duration.Input
readonly entityTerminationTimeout: Duration.Input
readonly entityMessagePollInterval: Duration.Input
readonly entityReplyPollInterval: Duration.Input
readonly refreshAssignmentsInterval: Duration.Input
readonly sendRetryInterval: Duration.Input
readonly runnerHealthCheckInterval: Duration.Input
readonly simulateRemoteSerialization: boolean
}
config = yield* import ShardingConfigShardingConfig.class ShardingConfigclass ShardingConfig {
key: Identifier;
Service: {
runnerAddress: Option.Option<RunnerAddress>;
runnerListenAddress: Option.Option<RunnerAddress>;
runnerShardWeight: number;
availableShardGroups: ReadonlyArray<string>;
assignedShardGroups: ReadonlyArray<string>;
shardsPerGroup: number;
shardLockRefreshInterval: Duration.Input;
shardLockExpiration: Duration.Input;
shardLockDisableAdvisory: boolean;
preemptiveShutdown: boolean;
entityMailboxCapacity: number | "unbounded";
entityMaxIdleTime: Duration.Input;
entityRegistrationTimeout: Duration.Input;
entityTerminationTimeout: Duration.Input;
entityMessagePollInterval: Duration.Input;
entityReplyPollInterval: Duration.Input;
refreshAssignmentsInterval: Duration.Input;
sendRetryInterval: Duration.Input;
runnerHealthCheckInterval: Duration.Input;
simulateRemoteSerialization: boolean;
};
of: (this: void, self: { readonly runnerAddress: Option.Option<RunnerAddress>; readonly runnerListenAddress: Option.Option<RunnerAddress>; readonly runnerShardWeight: number; readonly availableShardGroups: ReadonlyArray<string>; readonly assig…;
context: (self: { readonly runnerAddress: Option.Option<RunnerAddress>; readonly runnerListenAddress: Option.Option<RunnerAddress>; readonly runnerShardWeight: number; readonly availableShardGroups: ReadonlyArray<string>; readonly assignedShardGrou…;
use: (f: (service: { readonly runnerAddress: Option.Option<RunnerAddress>; readonly runnerListenAddress: Option.Option<RunnerAddress>; readonly runnerShardWeight: number; readonly availableShardGroups: ReadonlyArray<string>; readonly assignedSh…;
useSync: (f: (service: { readonly runnerAddress: Option.Option<RunnerAddress>; readonly runnerListenAddress: Option.Option<RunnerAddress>; readonly runnerShardWeight: number; readonly availableShardGroups: ReadonlyArray<string>; readonly assignedSh…;
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;
}
Represents the configuration for the Sharding service on a given runner.
ShardingConfig
const const listenAddress: Option.Option<RunnerAddress>listenAddress = import OptionOption.const orElse: {
<B>(that: LazyArg<Option<B>>): <A>(
self: Option<A>
) => Option<B | A>
<A, B>(
self: Option<A>,
that: LazyArg<Option<B>>
): Option<A | B>
}
Returns the fallback Option if self is None; otherwise returns self.
When to use
Use when you need a lazy fallback Option, such as when building priority
chains of optional values.
Details
Some → returns self unchanged
None → evaluates and returns that()
that is lazily evaluated
Example (Providing a fallback Option)
import { Option } from "effect"
console.log(Option.none().pipe(Option.orElse(() => Option.some("b"))))
// Output: { _id: 'Option', _tag: 'Some', value: 'b' }
console.log(Option.some("a").pipe(Option.orElse(() => Option.some("b"))))
// Output: { _id: 'Option', _tag: 'Some', value: 'a' }
orElse(const config: {
readonly runnerAddress: Option.Option<RunnerAddress>
readonly runnerListenAddress: Option.Option<RunnerAddress>
readonly runnerShardWeight: number
readonly availableShardGroups: ReadonlyArray<string>
readonly assignedShardGroups: ReadonlyArray<string>
readonly shardsPerGroup: number
readonly shardLockRefreshInterval: Duration.Input
readonly shardLockExpiration: Duration.Input
readonly shardLockDisableAdvisory: boolean
readonly preemptiveShutdown: boolean
readonly entityMailboxCapacity:
| number
| "unbounded"
readonly entityMaxIdleTime: Duration.Input
readonly entityRegistrationTimeout: Duration.Input
readonly entityTerminationTimeout: Duration.Input
readonly entityMessagePollInterval: Duration.Input
readonly entityReplyPollInterval: Duration.Input
readonly refreshAssignmentsInterval: Duration.Input
readonly sendRetryInterval: Duration.Input
readonly runnerHealthCheckInterval: Duration.Input
readonly simulateRemoteSerialization: boolean
}
config.runnerListenAddress: Option.Option<RunnerAddress>The listen address for the current runner.
Defaults to the runnerAddress.
runnerListenAddress, () => const config: {
readonly runnerAddress: Option.Option<RunnerAddress>
readonly runnerListenAddress: Option.Option<RunnerAddress>
readonly runnerShardWeight: number
readonly availableShardGroups: ReadonlyArray<string>
readonly assignedShardGroups: ReadonlyArray<string>
readonly shardsPerGroup: number
readonly shardLockRefreshInterval: Duration.Input
readonly shardLockExpiration: Duration.Input
readonly shardLockDisableAdvisory: boolean
readonly preemptiveShutdown: boolean
readonly entityMailboxCapacity:
| number
| "unbounded"
readonly entityMaxIdleTime: Duration.Input
readonly entityRegistrationTimeout: Duration.Input
readonly entityTerminationTimeout: Duration.Input
readonly entityMessagePollInterval: Duration.Input
readonly entityReplyPollInterval: Duration.Input
readonly refreshAssignmentsInterval: Duration.Input
readonly sendRetryInterval: Duration.Input
readonly runnerHealthCheckInterval: Duration.Input
readonly simulateRemoteSerialization: boolean
}
config.runnerAddress: Option.Option<RunnerAddress>The address for the current runner that other runners can use to
communicate with it.
If None, the runner is not part of the cluster and will be in a client-only
mode.
runnerAddress)
if (import OptionOption.const isNone: <A>(
self: Option<A>
) => self is None<A>
Checks whether an Option is None (absent).
When to use
Use when you need to branch on an absent Option before accessing .value.
Details
- Acts as a type guard, narrowing to
None<A>
Example (Checking for None)
import { Option } from "effect"
console.log(Option.isNone(Option.some(1)))
// Output: false
console.log(Option.isNone(Option.none()))
// Output: true
isNone(const listenAddress: Option.Option<RunnerAddress>listenAddress)) {
return yield* import EffectEffect.const die: (
defect: unknown
) => Effect<never>
Creates an effect that terminates a fiber with a specified error.
When to use
Use when you need an Effect to report an unrecoverable defect instead of a
typed error.
Details
The die function is used to signal a defect, which represents a critical
and unexpected error in the code. When invoked, it produces an effect that
does not handle the error and instead terminates the fiber.
The error channel of the resulting effect is of type never, indicating that
it cannot recover from this failure.
Example (Failing on division by zero)
import { Effect } from "effect"
const divide = (a: number, b: number) =>
b === 0
? Effect.die(new Error("Cannot divide by zero"))
: Effect.succeed(a / b)
// ┌─── Effect<number, never, never>
// ▼
const program = divide(1, 0)
Effect.runPromise(program).catch(console.error)
// Output:
// (FiberFailure) Error: Cannot divide by zero
// ...stack trace...
die("NodeClusterHttp.layerHttpServer: ShardingConfig.runnerAddress is None")
}
return import NodeHttpServerNodeHttpServer.const layer: (
evaluate: LazyArg<Http.Server>,
options: Net.ListenOptions & {
readonly disablePreemptiveShutdown?:
| boolean
| undefined
readonly gracefulShutdownTimeout?:
| Duration.Input
| undefined
}
) => Layer.Layer<
| HttpServer.HttpServer
| NodeServices.NodeServices
| HttpPlatform.HttpPlatform
| Etag.Generator,
ServeError
>
Provides a Node HttpServer together with the Node HTTP platform, ETag, and
core platform services required to serve requests.
layer(import createServercreateServer, const listenAddress: Option.Some<RunnerAddress>const listenAddress: {
_tag: "Some";
_op: "Some";
value: A;
valueOrUndefined: A;
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;
}
listenAddress.Some<RunnerAddress>.value: RunnerAddress(property) Some<RunnerAddress>.value: {
toString: () => string;
host: string;
port: number;
}
value)
}).Pipeable.pipe<Effect.Effect<Layer.Layer<HttpPlatform | HttpServer | NodeServices | Etag.Generator, ServeError, never>, never, ShardingConfig.ShardingConfig>, Layer.Layer<HttpPlatform | HttpServer | NodeServices | Etag.Generator, ServeError, ShardingConfig.ShardingConfig>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Layer.Layer<HttpPlatform | HttpServer | NodeServices | Etag.Generator, ServeError, never>, never, ShardingConfig.ShardingConfig>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(import LayerLayer.const unwrap: <A, E1, R1, E, R>(
self: Effect<Layer<A, E1, R1>, E, R>
) => Layer<
A,
E | E1,
R1 | Exclude<R, Scope.Scope>
>
Unwraps a Layer from an Effect, flattening the nested structure.
When to use
Use when you have an Effect that produces a Layer and you want to
use that layer directly.
Details
The resulting Layer will have the combined error and dependency types from
both the outer Effect and the inner Layer.
Example (Unwrapping an effectful layer)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layerEffect = Effect.succeed(
Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) })
)
const unwrappedLayer = Layer.unwrap(layerEffect)
unwrap)