@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.
- package/dist/cjs/HttpApiBuilder.js +44 -4
- package/dist/cjs/HttpApiBuilder.js.map +1 -1
- package/dist/cjs/WorkerRunner.js +19 -3
- package/dist/cjs/WorkerRunner.js.map +1 -1
- package/dist/cjs/internal/workerRunner.js +22 -14
- package/dist/cjs/internal/workerRunner.js.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/WorkerRunner.d.ts +34 -7
- package/dist/dts/WorkerRunner.d.ts.map +1 -1
- package/dist/esm/HttpApiBuilder.js +41 -3
- package/dist/esm/HttpApiBuilder.js.map +1 -1
- package/dist/esm/WorkerRunner.js +18 -2
- package/dist/esm/WorkerRunner.js.map +1 -1
- package/dist/esm/internal/workerRunner.js +20 -11
- package/dist/esm/internal/workerRunner.js.map +1 -1
- package/package.json +2 -2
- package/src/HttpApiBuilder.ts +47 -3
- package/src/WorkerRunner.ts +43 -13
- package/src/internal/workerRunner.ts +104 -104
|
@@ -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
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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(
|
|
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> =>
|
|
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
|
+
}))
|