@effect/platform 0.75.4 → 0.76.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,13 @@
1
1
  import * as Cause from "effect/Cause"
2
2
  import * as Chunk from "effect/Chunk"
3
3
  import * as Context from "effect/Context"
4
+ import * as Deferred from "effect/Deferred"
4
5
  import * as Effect from "effect/Effect"
5
6
  import * as Either from "effect/Either"
6
7
  import * as Fiber from "effect/Fiber"
8
+ import * as FiberId from "effect/FiberId"
7
9
  import { pipe } from "effect/Function"
8
10
  import * as Layer from "effect/Layer"
9
- import * as Schedule from "effect/Schedule"
10
11
  import * as Schema from "effect/Schema"
11
12
  import type * as Scope from "effect/Scope"
12
13
  import * as Stream from "effect/Stream"
@@ -26,125 +27,114 @@ export const PlatformRunner = Context.GenericTag<WorkerRunner.PlatformRunner>(
26
27
  )
27
28
 
28
29
  /** @internal */
29
- export const run = <I, E, R, O>(
30
+ export const CloseLatch = Context.Reference<WorkerRunner.CloseLatch>()("@effect/platform/WorkerRunner/CloseLatch", {
31
+ defaultValue: () => Deferred.unsafeMake<void, WorkerError>(FiberId.none)
32
+ })
33
+
34
+ /** @internal */
35
+ export const layerCloseLatch = Layer.effect(CloseLatch, Deferred.make())
36
+
37
+ /** @internal */
38
+ export const make = Effect.fnUntraced(function*<I, E, R, O>(
30
39
  process: (request: I) => Stream.Stream<O, E, R> | Effect.Effect<O, E, R>,
31
40
  options?: WorkerRunner.Runner.Options<I, O, E>
32
- ) =>
33
- Effect.gen(function*() {
34
- const platform = yield* PlatformRunner
35
- const backing = yield* platform.start<Worker.Worker.Request<I>, Worker.Worker.Response<E>>()
36
- const fiberMap = new Map<number, Fiber.Fiber<unknown, unknown>>()
41
+ ) {
42
+ const platform = yield* PlatformRunner
43
+ const closeLatch = yield* CloseLatch
44
+ const backing = yield* platform.start<Worker.Worker.Request<I>, Worker.Worker.Response<E>>(closeLatch)
45
+ const fiberMap = new Map<number, Fiber.Fiber<unknown, unknown>>()
37
46
 
38
- return yield* backing.run((portId, [id, kind, data, span]): Effect.Effect<void, WorkerError, R> => {
39
- if (kind === 1) {
40
- const fiber = fiberMap.get(id)
41
- if (!fiber) return Effect.void
42
- return Fiber.interrupt(fiber)
43
- }
47
+ yield* backing.run((portId, [id, kind, data, span]): Effect.Effect<void, WorkerError, R> => {
48
+ if (kind === 1) {
49
+ const fiber = fiberMap.get(id)
50
+ if (!fiber) return Effect.void
51
+ return Fiber.interrupt(fiber)
52
+ }
44
53
 
45
- return Effect.withFiberRuntime<I, WorkerError>((fiber) => {
46
- fiberMap.set(id, fiber)
47
- return options?.decode ? options.decode(data) : Effect.succeed(data)
48
- }).pipe(
49
- Effect.flatMap((input) => {
50
- const collector = Transferable.unsafeMakeCollector()
51
- const stream = process(input)
52
- let effect = Effect.isEffect(stream) ?
53
- Effect.flatMap(stream, (out) =>
54
- pipe(
55
- options?.encodeOutput
56
- ? Effect.provideService(options.encodeOutput(input, out), Transferable.Collector, collector)
57
- : Effect.succeed(out),
58
- Effect.flatMap((payload) => backing.send(portId, [id, 0, [payload]], collector.unsafeRead()))
59
- )) :
54
+ return Effect.withFiberRuntime<I, WorkerError>((fiber) => {
55
+ fiberMap.set(id, fiber)
56
+ return options?.decode ? options.decode(data) : Effect.succeed(data)
57
+ }).pipe(
58
+ Effect.flatMap((input) => {
59
+ const collector = Transferable.unsafeMakeCollector()
60
+ const stream = process(input)
61
+ let effect = Effect.isEffect(stream) ?
62
+ Effect.flatMap(stream, (out) =>
60
63
  pipe(
61
- stream,
62
- Stream.runForEachChunk((chunk) => {
63
- if (options?.encodeOutput === undefined) {
64
- const payload = Chunk.toReadonlyArray(chunk)
65
- return backing.send(portId, [id, 0, payload])
66
- }
64
+ options?.encodeOutput
65
+ ? Effect.provideService(options.encodeOutput(input, out), Transferable.Collector, collector)
66
+ : Effect.succeed(out),
67
+ Effect.flatMap((payload) => backing.send(portId, [id, 0, [payload]], collector.unsafeRead()))
68
+ )) :
69
+ pipe(
70
+ stream,
71
+ Stream.runForEachChunk((chunk) => {
72
+ if (options?.encodeOutput === undefined) {
73
+ const payload = Chunk.toReadonlyArray(chunk)
74
+ return backing.send(portId, [id, 0, payload])
75
+ }
67
76
 
68
- collector.unsafeClear()
69
- return pipe(
70
- Effect.forEach(chunk, (data) => options.encodeOutput!(input, data)),
71
- Effect.provideService(Transferable.Collector, collector),
72
- Effect.flatMap((payload) => backing.send(portId, [id, 0, payload], collector.unsafeRead()))
73
- )
74
- }),
75
- Effect.andThen(backing.send(portId, [id, 1]))
76
- )
77
+ collector.unsafeClear()
78
+ return pipe(
79
+ Effect.forEach(chunk, (data) => options.encodeOutput!(input, data)),
80
+ Effect.provideService(Transferable.Collector, collector),
81
+ Effect.flatMap((payload) => backing.send(portId, [id, 0, payload], collector.unsafeRead()))
82
+ )
83
+ }),
84
+ Effect.andThen(backing.send(portId, [id, 1]))
85
+ )
77
86
 
78
- if (span) {
79
- effect = Effect.withParentSpan(effect, {
80
- _tag: "ExternalSpan",
81
- traceId: span[0],
82
- spanId: span[1],
83
- sampled: span[2],
84
- context: Context.empty()
85
- })
86
- }
87
+ if (span) {
88
+ effect = Effect.withParentSpan(effect, {
89
+ _tag: "ExternalSpan",
90
+ traceId: span[0],
91
+ spanId: span[1],
92
+ sampled: span[2],
93
+ context: Context.empty()
94
+ })
95
+ }
87
96
 
88
- return Effect.uninterruptibleMask((restore) =>
89
- restore(effect).pipe(
90
- Effect.catchIf(
91
- isWorkerError,
92
- (error) => backing.send(portId, [id, 3, WorkerError.encodeCause(Cause.fail(error))])
93
- ),
94
- Effect.catchAllCause((cause) =>
95
- Either.match(Cause.failureOrCause(cause), {
96
- onLeft: (error) => {
97
- collector.unsafeClear()
98
- return pipe(
99
- options?.encodeError
100
- ? Effect.provideService(
101
- options.encodeError(input, error),
102
- Transferable.Collector,
103
- collector
104
- )
105
- : Effect.succeed(error),
106
- Effect.flatMap((payload) =>
107
- backing.send(portId, [id, 2, payload as any], collector.unsafeRead())
108
- ),
109
- Effect.catchAllCause((cause) => backing.send(portId, [id, 3, WorkerError.encodeCause(cause)]))
110
- )
111
- },
112
- onRight: (cause) => backing.send(portId, [id, 3, WorkerError.encodeCause(cause)])
113
- })
114
- )
97
+ return Effect.uninterruptibleMask((restore) =>
98
+ restore(effect).pipe(
99
+ Effect.catchIf(
100
+ isWorkerError,
101
+ (error) => backing.send(portId, [id, 3, WorkerError.encodeCause(Cause.fail(error))])
102
+ ),
103
+ Effect.catchAllCause((cause) =>
104
+ Either.match(Cause.failureOrCause(cause), {
105
+ onLeft: (error) => {
106
+ collector.unsafeClear()
107
+ return pipe(
108
+ options?.encodeError
109
+ ? Effect.provideService(
110
+ options.encodeError(input, error),
111
+ Transferable.Collector,
112
+ collector
113
+ )
114
+ : Effect.succeed(error),
115
+ Effect.flatMap((payload) => backing.send(portId, [id, 2, payload as any], collector.unsafeRead())),
116
+ Effect.catchAllCause((cause) => backing.send(portId, [id, 3, WorkerError.encodeCause(cause)]))
117
+ )
118
+ },
119
+ onRight: (cause) => backing.send(portId, [id, 3, WorkerError.encodeCause(cause)])
120
+ })
115
121
  )
116
122
  )
117
- }),
118
- Effect.ensuring(Effect.sync(() => fiberMap.delete(id)))
119
- )
120
- })
121
- })
122
-
123
- /** @internal */
124
- export const make = <I, E, R, O>(
125
- process: (request: I) => Stream.Stream<O, E, R> | Effect.Effect<O, E, R>,
126
- options?: WorkerRunner.Runner.Options<I, O, E>
127
- ): Effect.Effect<void, WorkerError, WorkerRunner.PlatformRunner | R | Scope.Scope> =>
128
- Effect.withFiberRuntime<void, never, WorkerRunner.PlatformRunner | R | Scope.Scope>((fiber) =>
129
- run(process, options).pipe(
130
- Effect.tapErrorCause((cause) => Cause.isInterruptedOnly(cause) ? Effect.void : Effect.logWarning(cause)),
131
- Effect.retry(Schedule.spaced(1000)),
132
- Effect.annotateLogs({
133
- package: "@effect/platform-node",
134
- module: "WorkerRunner"
123
+ )
135
124
  }),
136
- Effect.ensuring(Fiber.interruptAsFork(fiber, fiber.id())),
137
- Effect.interruptible,
138
- Effect.forkScoped,
139
- Effect.asVoid
125
+ Effect.ensuring(Effect.sync(() => fiberMap.delete(id)))
140
126
  )
141
- )
127
+ })
128
+ })
142
129
 
143
130
  /** @internal */
144
131
  export const layer = <I, E, R, O>(
145
132
  process: (request: I) => Stream.Stream<O, E, R> | Effect.Effect<O, E, R>,
146
133
  options?: WorkerRunner.Runner.Options<I, O, E>
147
- ): Layer.Layer<never, WorkerError, WorkerRunner.PlatformRunner | R> => Layer.scopedDiscard(make(process, options))
134
+ ): Layer.Layer<never, WorkerError, WorkerRunner.PlatformRunner | R> =>
135
+ Layer.scopedDiscard(make(process, options)).pipe(
136
+ Layer.provide(layerCloseLatch)
137
+ )
148
138
 
149
139
  /** @internal */
150
140
  export const makeSerialized = <
@@ -216,4 +206,14 @@ export const layerSerialized = <
216
206
  | R
217
207
  | WorkerRunner.PlatformRunner
218
208
  | WorkerRunner.SerializedRunner.HandlersContext<Handlers>
219
- > => Layer.scopedDiscard(makeSerialized(schema, handlers))
209
+ > => Layer.scopedDiscard(makeSerialized(schema, handlers)).pipe(Layer.provide(layerCloseLatch))
210
+
211
+ /** @internal */
212
+ export const launch = <A, E, R>(layer: Layer.Layer<A, E, R>): Effect.Effect<void, E | WorkerError, R> =>
213
+ Effect.scopedWith(Effect.fnUntraced(function*(scope) {
214
+ const context = yield* Layer.buildWithScope(Layer.merge(layer, layerCloseLatch), scope)
215
+ const closeLatch = Context.get(context, CloseLatch)
216
+ return yield* Effect.never.pipe(
217
+ Effect.raceFirst(Deferred.await(closeLatch))
218
+ )
219
+ }))