(permits: number): Effect.Effect<TxSemaphore>Creates a new TxSemaphore with the specified number of permits.
When to use
Use to create a transactional semaphore with a fixed permit capacity.
Example (Creating a semaphore)
import { Console, Effect, TxSemaphore } from "effect"
// Create a semaphore for managing concurrent access to a resource pool
const program = Effect.gen(function*() {
// Create a semaphore with 3 permits for a connection pool
const connectionSemaphore = yield* TxSemaphore.make(3)
// Check initial state
const available = yield* TxSemaphore.available(connectionSemaphore)
const capacity = yield* TxSemaphore.capacity(connectionSemaphore)
yield* Console.log(
`Created semaphore with ${capacity} permits, ${available} available`
)
// Output: "Created semaphore with 3 permits, 3 available"
})export const const make: (
permits: number
) => Effect.Effect<TxSemaphore>
Creates a new TxSemaphore with the specified number of permits.
When to use
Use to create a transactional semaphore with a fixed permit capacity.
Example (Creating a semaphore)
import { Console, Effect, TxSemaphore } from "effect"
// Create a semaphore for managing concurrent access to a resource pool
const program = Effect.gen(function*() {
// Create a semaphore with 3 permits for a connection pool
const connectionSemaphore = yield* TxSemaphore.make(3)
// Check initial state
const available = yield* TxSemaphore.available(connectionSemaphore)
const capacity = yield* TxSemaphore.capacity(connectionSemaphore)
yield* Console.log(
`Created semaphore with ${capacity} permits, ${available} available`
)
// Output: "Created semaphore with 3 permits, 3 available"
})
make = (permits: numberpermits: number): import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<TxSemaphore> =>
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
>
}
gen(function*() {
if (permits: numberpermits < 0) {
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(new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error("Permits must be non-negative"))
}
const const permitsRef: TxRef.TxRef<number>const permitsRef: {
version: number;
pending: Map<unknown, () => void>;
value: 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; <…;
}
permitsRef = yield* import TxRefTxRef.const make: <number>(
initial: number
) => Effect.Effect<
TxRef.TxRef<number>,
never,
never
>
Creates a new TxRef with the specified initial value.
When to use
Use to create a TxRef inside an Effect workflow.
Example (Creating transactional references)
import { Effect, TxRef } from "effect"
const program = Effect.gen(function*() {
// Create a transactional reference with initial value
const counter = yield* TxRef.make(0)
const name = yield* TxRef.make("Alice")
// Use in transactions
yield* Effect.tx(Effect.gen(function*() {
yield* TxRef.set(counter, 42)
yield* TxRef.set(name, "Bob")
}))
console.log(yield* TxRef.get(counter)) // 42
console.log(yield* TxRef.get(name)) // "Bob"
})
make(permits: numberpermits)
return const makeTxSemaphore: (
permitsRef: TxRef.TxRef<number>,
capacity: number
) => TxSemaphore
makeTxSemaphore(const permitsRef: TxRef.TxRef<number>const permitsRef: {
version: number;
pending: Map<unknown, () => void>;
value: 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; <…;
}
permitsRef, permits: numberpermits)
}).Pipeable.pipe<Effect.Effect<TxSemaphore, never, never>, Effect.Effect<TxSemaphore, never, never>>(this: Effect.Effect<TxSemaphore, never, never>, ab: (_: Effect.Effect<TxSemaphore, never, never>) => Effect.Effect<TxSemaphore, never, never>): Effect.Effect<TxSemaphore, never, never> (+21 overloads)pipe(import EffectEffect.const tx: <A, E, R>(
effect: Effect<A, E, R>
) => Effect<A, E, Exclude<R, Transaction>>
Defines a transaction boundary. Transactions are "all or nothing" with respect to changes
made to transactional values (i.e. TxRef) that occur within the transaction body.
Details
If called inside an active transaction, tx composes with the current transaction and reuses
its journal and retry state instead of creating a nested boundary.
Effect transactions are optimistic with retry. A transaction is retried when
its body explicitly calls Effect.txRetry and any accessed transactional
value changes, or when any accessed transactional value changes because a
different transaction commits before the current one.
The outermost tx call creates the transaction boundary and commits or rolls back the full
composed transaction.
Example (Running a transaction)
import { Effect, TxRef } from "effect"
const program = Effect.gen(function*() {
const ref1 = yield* TxRef.make(0)
const ref2 = yield* TxRef.make(0)
// Nested tx calls compose into the same transaction
yield* Effect.tx(Effect.gen(function*() {
yield* TxRef.set(ref1, 10)
yield* Effect.tx(TxRef.set(ref2, 20))
const sum = (yield* TxRef.get(ref1)) + (yield* TxRef.get(ref2))
console.log(`Transaction sum: ${sum}`)
}))
console.log(`Final ref1: ${yield* TxRef.get(ref1)}`) // 10
console.log(`Final ref2: ${yield* TxRef.get(ref2)}`) // 20
})
tx)