<A>(pubsub: PubSub.Subscription<A>): Stream<A>Creates a stream from a PubSub subscription.
When to use
Use when you already have a PubSub.Subscription and want to expose its
messages as a Stream, with Stream.take or cancellation controlling how
many values are consumed.
Example (Creating a stream from a PubSub subscription)
import { Console, Effect, PubSub, Stream } from "effect"
const program = Effect.scoped(Effect.gen(function*() {
const pubsub = yield* PubSub.unbounded<number>()
const subscription = yield* PubSub.subscribe(pubsub)
yield* PubSub.publish(pubsub, 1)
yield* PubSub.publish(pubsub, 2)
const stream = Stream.fromSubscription(subscription)
const values = yield* stream.pipe(Stream.take(2), Stream.runCollect)
yield* Console.log(values)
}))
Effect.runPromise(program)
// Output: [ 1, 2 ]export const const fromSubscription: <A>(
pubsub: PubSub.Subscription<A>
) => Stream<A>
Creates a stream from a PubSub subscription.
When to use
Use when you already have a PubSub.Subscription and want to expose its
messages as a Stream, with Stream.take or cancellation controlling how
many values are consumed.
Example (Creating a stream from a PubSub subscription)
import { Console, Effect, PubSub, Stream } from "effect"
const program = Effect.scoped(Effect.gen(function*() {
const pubsub = yield* PubSub.unbounded<number>()
const subscription = yield* PubSub.subscribe(pubsub)
yield* PubSub.publish(pubsub, 1)
yield* PubSub.publish(pubsub, 2)
const stream = Stream.fromSubscription(subscription)
const values = yield* stream.pipe(Stream.take(2), Stream.runCollect)
yield* Console.log(values)
}))
Effect.runPromise(program)
// Output: [ 1, 2 ]
fromSubscription = <function (type parameter) A in <A>(pubsub: PubSub.Subscription<A>): Stream<A>A>(pubsub: PubSub.Subscription<A>(parameter) pubsub: {
pubsub: PubSub.Atomic<any>;
subscribers: PubSub.Subscribers<any>;
subscription: PubSub.BackingSubscription<A>;
pollers: MutableList.MutableList<Deferred.Deferred<any>>;
shutdownHook: Latch.Latch;
shutdownFlag: MutableRef.MutableRef<boolean>;
strategy: PubSub.Strategy<any>;
replayWindow: PubSub.ReplayWindow<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; <…;
}
pubsub: import PubSubPubSub.interface Subscription<out A>A subscription represents a consumer's connection to a PubSub, allowing them to take messages.
Example (Taking messages from a subscription)
import { Effect, PubSub } from "effect"
const program = Effect.gen(function*() {
const pubsub = yield* PubSub.bounded<string>(10)
// Subscribe within a scope for automatic cleanup
yield* Effect.scoped(Effect.gen(function*() {
const subscription: PubSub.Subscription<string> = yield* PubSub.subscribe(
pubsub
)
yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"])
// Take individual messages
const message = yield* PubSub.take(subscription)
console.log(message) // "msg1"
// Take multiple messages
const messages = yield* PubSub.takeUpTo(subscription, 1)
console.log(messages) // ["msg2"]
const allMessages = yield* PubSub.takeAll(subscription)
console.log(allMessages) // ["msg3"]
}))
})
Subscription<function (type parameter) A in <A>(pubsub: PubSub.Subscription<A>): Stream<A>A>): interface Stream<out A, out E = never, out R = never>A Stream<A, E, R> describes a program that can emit many A values, fail
with E, and require R.
Details
Streams are pull-based with backpressure and emit chunks to amortize effect
evaluation. They support monadic composition and error handling similar to
Effect, adapted for multiple values.
Example (Creating and consuming streams)
import { Console, Effect, Stream } from "effect"
const program = Effect.gen(function*() {
yield* Stream.make(1, 2, 3).pipe(
Stream.map((n) => n * 2),
Stream.runForEach((n) => Console.log(n))
)
})
Effect.runPromise(program)
// Output:
// 2
// 4
// 6
Stream<function (type parameter) A in <A>(pubsub: PubSub.Subscription<A>): Stream<A>A> =>
const fromChannel: <
Arr extends Arr.NonEmptyReadonlyArray<any>,
E,
R
>(
channel: Channel.Channel<
Arr,
E,
void,
unknown,
unknown,
unknown,
R
>
) => Stream<
Arr extends Arr.NonEmptyReadonlyArray<infer A>
? A
: never,
E,
R
>
Creates a stream from a array-emitting Channel.
Example (Creating a stream from an array-emitting channel)
import { Channel, Console, Effect, Stream } from "effect"
const program = Effect.gen(function*() {
const channel = Channel.succeed([1, 2, 3] as const)
const stream = Stream.fromChannel(channel)
const result = yield* Stream.runCollect(stream)
yield* Console.log(result)
})
// Output: [ 1, 2, 3 ]
fromChannel(import ChannelChannel.const fromSubscriptionArray: <A>(
subscription: PubSub.Subscription<A>
) => Channel<Arr.NonEmptyReadonlyArray<A>>
Creates a channel from a PubSub subscription that outputs arrays of values.
Details
This constructor creates a channel that reads from a PubSub subscription and outputs
arrays of values in chunks. It's useful when you want to process multiple values at once
for better performance.
Example (Batching subscription values)
import { Channel, Data, Effect, PubSub } from "effect"
class StreamError extends Data.TaggedError("StreamError")<{
readonly message: string
}> {}
const program = Effect.gen(function*() {
const pubsub = yield* PubSub.bounded<number>(16)
const subscription = yield* PubSub.subscribe(pubsub)
// Create a channel that reads arrays of values
const channel = Channel.fromSubscriptionArray(subscription)
// Publish some values
yield* PubSub.publish(pubsub, 1)
yield* PubSub.publish(pubsub, 2)
yield* PubSub.publish(pubsub, 3)
yield* PubSub.publish(pubsub, 4)
// The channel will output arrays like [1, 2, 3] and [4]
return channel
})
Example (Processing subscription values in batches)
import { Channel, Data, Effect, PubSub } from "effect"
class BatchProcessingError extends Data.TaggedError("BatchProcessingError")<{
readonly reason: string
}> {}
const batchProcessor = Effect.gen(function*() {
const pubsub = yield* PubSub.bounded<string>(32)
const subscription = yield* PubSub.subscribe(pubsub)
// Create a channel that processes items in batches
const batchChannel = Channel.fromSubscriptionArray(subscription)
// Transform to process each batch
const processedChannel = Channel.map(batchChannel, (batch) => {
console.log(`Processing batch of ${batch.length} items:`, batch)
return batch.map((item) => item.toUpperCase())
})
return processedChannel
})
Example (Aggregating subscription metrics)
import { Channel, Effect, PubSub } from "effect"
const metricsAggregator = Effect.gen(function*() {
const metricsPubSub = yield* PubSub.bounded<
{ timestamp: number; value: number }
>(100)
const subscription = yield* PubSub.subscribe(metricsPubSub)
// Create a channel that collects metrics in chunks
const metricsChannel = Channel.fromSubscriptionArray(subscription)
// Transform to calculate aggregate statistics
const aggregatedChannel = Channel.map(metricsChannel, (metrics) => {
const values = metrics.map((m) => m.value)
const sum = values.reduce((a, b) => a + b, 0)
const avg = sum / values.length
const min = Math.min(...values)
const max = Math.max(...values)
return {
count: values.length,
sum,
average: avg,
min,
max,
firstTimestamp: Math.min(...metrics.map((m) => m.timestamp)),
lastTimestamp: Math.max(...metrics.map((m) => m.timestamp))
}
})
return aggregatedChannel
})
fromSubscriptionArray(pubsub: PubSub.Subscription<A>(parameter) pubsub: {
pubsub: PubSub.Atomic<any>;
subscribers: PubSub.Subscribers<any>;
subscription: PubSub.BackingSubscription<A>;
pollers: MutableList.MutableList<Deferred.Deferred<any>>;
shutdownHook: Latch.Latch;
shutdownFlag: MutableRef.MutableRef<boolean>;
strategy: PubSub.Strategy<any>;
replayWindow: PubSub.ReplayWindow<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; <…;
}
pubsub))