You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/* eslint-disable @typescript-eslint/no-floating-promises *//* eslint-disable functional/no-expression-statements *//* eslint-disable functional/no-return-void */importtype{StreamEmit}from"effect";import{Effect,Stream,Chunk,Fiber}from"effect";import{EventEmitter}from"node:events";exportconstexample=Effect.gen(function*(){constemitter=newEventEmitter();conststream=Stream.async((emit: StreamEmit.Emit<never,never,unknown,void>)=>{constcallback=(a: unknown): void=>{emit(Effect.succeed(Chunk.of(a)));};emitter.on("test",callback);},);conststreamEffect=Stream.runForEach(stream,(a)=>{returnEffect.logWarning(a);});constfiber=yield*Effect.fork(streamEffect);// yield now to let the fiber begin executionyield*Effect.yieldNow();// Comment out this second yield to reproduce the issueyield*Effect.yieldNow();emitter.emit("test","test event");yield*Fiber.interrupt(fiber);});
If you run this example effect in a wider program, e.g. via yield* example; in a generator, you'll see the expected logging output:
[16:04:28.376] WARN (#37): test event
If you comment out the second yield, you'll see no such logging. This is the part that is surprising to me.
I've experimented with omitting the interrupt, Stream.asyncEffect instead of Stream.async, using forkDaemon or forkScoped (with a wide, long-lived scope) and a handful of other things but the only way I've been able to make this work is by adding the second yield (or with a Effect.sleep(100) in place of the second yield).
I think I have an intuition for what's going wrong - pumping the event loop just once isn't enough for the stream initialization to subscribe to the event emitter before the event is emitted. The second yield (or sleep) puts the main fiber back on the end of the event loop, giving the stream initialization a chance to run before the main fiber emits the event.
What I can't quite work out is what I'm doing wrong or how to make this work without the kludge.
What is the expected behavior?
Stream subscribes to events before the first event is emitted, with a single yieldNow at most.
What version of Effect is running?
3.12.0
What steps can reproduce the bug?
Please see a minimal reproducer below.
Basically, it does the following:
Stream.async
that subscribes to an event from that emitterIf you run this example effect in a wider program, e.g. via
yield* example;
in a generator, you'll see the expected logging output:If you comment out the second yield, you'll see no such logging. This is the part that is surprising to me.
I've experimented with omitting the interrupt,
Stream.asyncEffect
instead ofStream.async
, usingforkDaemon
orforkScoped
(with a wide, long-lived scope) and a handful of other things but the only way I've been able to make this work is by adding the second yield (or with aEffect.sleep(100)
in place of the second yield).I think I have an intuition for what's going wrong - pumping the event loop just once isn't enough for the stream initialization to subscribe to the event emitter before the event is emitted. The second yield (or sleep) puts the main fiber back on the end of the event loop, giving the stream initialization a chance to run before the main fiber emits the event.
What I can't quite work out is what I'm doing wrong or how to make this work without the kludge.
What is the expected behavior?
Stream subscribes to events before the first event is emitted, with a single
yieldNow
at most.What do you see instead?
Two
yieldNow
s required.Additional information
Node v23.3.0 + these additional Effect packages:
The text was updated successfully, but these errors were encountered: