@livestore/utils 0.0.55-dev.1 → 0.0.55-dev.3

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.
Files changed (42) hide show
  1. package/dist/.tsbuildinfo.json +1 -1
  2. package/dist/effect/BrowserChannel.d.ts +25 -0
  3. package/dist/effect/BrowserChannel.d.ts.map +1 -0
  4. package/dist/effect/BrowserChannel.js +32 -0
  5. package/dist/effect/BrowserChannel.js.map +1 -0
  6. package/dist/effect/Effect.d.ts +3 -1
  7. package/dist/effect/Effect.d.ts.map +1 -1
  8. package/dist/effect/Effect.js +2 -0
  9. package/dist/effect/Effect.js.map +1 -1
  10. package/dist/effect/Stream.d.ts +1 -0
  11. package/dist/effect/Stream.d.ts.map +1 -1
  12. package/dist/effect/Stream.js +1 -0
  13. package/dist/effect/Stream.js.map +1 -1
  14. package/dist/effect/SubscriptionRef.d.ts +2 -2
  15. package/dist/effect/SubscriptionRef.d.ts.map +1 -1
  16. package/dist/effect/SubscriptionRef.js +2 -3
  17. package/dist/effect/SubscriptionRef.js.map +1 -1
  18. package/dist/effect/index.d.ts +3 -6
  19. package/dist/effect/index.d.ts.map +1 -1
  20. package/dist/effect/index.js +3 -8
  21. package/dist/effect/index.js.map +1 -1
  22. package/package.json +14 -14
  23. package/src/effect/BrowserChannel.ts +90 -0
  24. package/src/effect/Effect.ts +9 -1
  25. package/src/effect/Stream.ts +5 -0
  26. package/src/effect/SubscriptionRef.ts +3 -11
  27. package/src/effect/index.ts +4 -8
  28. package/dist/effect/Schema.d.ts +0 -4
  29. package/dist/effect/Schema.d.ts.map +0 -1
  30. package/dist/effect/Schema.js +0 -15
  31. package/dist/effect/Schema.js.map +0 -1
  32. package/src/effect/browser-worker-tmp/BrowserWorker.ts +0 -26
  33. package/src/effect/browser-worker-tmp/BrowserWorkerRunner.ts +0 -14
  34. package/src/effect/browser-worker-tmp/internal/worker.ts +0 -71
  35. package/src/effect/browser-worker-tmp/internal/workerRunner.ts +0 -119
  36. package/src/effect/browser-worker-tmp/port-platform-runner.ts +0 -74
  37. package/src/effect/worker-tmp/Worker.ts +0 -374
  38. package/src/effect/worker-tmp/WorkerError.ts +0 -79
  39. package/src/effect/worker-tmp/WorkerRunner.ts +0 -181
  40. package/src/effect/worker-tmp/internal/worker.ts +0 -417
  41. package/src/effect/worker-tmp/internal/workerError.ts +0 -6
  42. package/src/effect/worker-tmp/internal/workerRunner.ts +0 -237
@@ -1,79 +0,0 @@
1
- /**
2
- * @since 1.0.0
3
- */
4
- import * as Schema from '@effect/schema/Schema'
5
- import type * as Cause from 'effect/Cause'
6
- import * as Inspectable from 'effect/Inspectable'
7
- import * as Predicate from 'effect/Predicate'
8
-
9
- import * as internal from './internal/workerError.js'
10
-
11
- /**
12
- * @since 1.0.0
13
- * @category type ids
14
- */
15
- export const WorkerErrorTypeId: unique symbol = internal.WorkerErrorTypeId
16
-
17
- /**
18
- * @since 1.0.0
19
- * @category type ids
20
- */
21
- export type WorkerErrorTypeId = typeof WorkerErrorTypeId
22
-
23
- /**
24
- * @since 1.0.0
25
- * @category predicates
26
- */
27
- export const isWorkerError = (u: unknown): u is WorkerError => Predicate.hasProperty(u, WorkerErrorTypeId)
28
-
29
- /**
30
- * @since 1.0.0
31
- * @category errors
32
- */
33
- export class WorkerError extends Schema.TaggedError<WorkerError>()('WorkerError', {
34
- reason: Schema.Literal('spawn', 'decode', 'send', 'unknown', 'encode'),
35
- error: Schema.Defect,
36
- }) {
37
- /**
38
- * @since 1.0.0
39
- */
40
- readonly [WorkerErrorTypeId]: WorkerErrorTypeId = WorkerErrorTypeId
41
-
42
- /**
43
- * @since 1.0.0
44
- */
45
- static readonly Cause: Schema.Schema<Cause.Cause<WorkerError>, Schema.CauseEncoded<WorkerErrorFrom, unknown>> =
46
- Schema.Cause({ error: this, defect: Schema.Defect })
47
-
48
- /**
49
- * @since 1.0.0
50
- */
51
- static readonly encodeCause: (a: Cause.Cause<WorkerError>) => Schema.CauseEncoded<WorkerErrorFrom, unknown> =
52
- Schema.encodeSync(this.Cause)
53
-
54
- /**
55
- * @since 1.0.0
56
- */
57
- static readonly decodeCause: (u: Schema.CauseEncoded<WorkerErrorFrom, Schema.Defect>) => Cause.Cause<WorkerError> =
58
- Schema.decodeSync(this.Cause)
59
-
60
- /**
61
- * @since 1.0.0
62
- */
63
- get message() {
64
- const message = Predicate.hasProperty(this.error, 'message')
65
- ? this.error.message
66
- : Inspectable.toStringUnknown(this.error, undefined)
67
- return `${this.reason}: ${message}`
68
- }
69
- }
70
-
71
- /**
72
- * @since 1.0.0
73
- * @category errors
74
- */
75
- export interface WorkerErrorFrom {
76
- readonly _tag: 'WorkerError'
77
- readonly reason: 'spawn' | 'decode' | 'send' | 'unknown' | 'encode'
78
- readonly error: unknown
79
- }
@@ -1,181 +0,0 @@
1
- /**
2
- * @since 1.0.0
3
- */
4
- import type * as Schema from '@effect/schema/Schema'
5
- import type * as Serializable from '@effect/schema/Serializable'
6
- import type * as Context from 'effect/Context'
7
- import type * as Effect from 'effect/Effect'
8
- import type * as Layer from 'effect/Layer'
9
- import type * as Queue from 'effect/Queue'
10
- import type * as Scope from 'effect/Scope'
11
- import type * as Stream from 'effect/Stream'
12
-
13
- import * as internal from './internal/workerRunner.js'
14
- import type { WorkerError } from './WorkerError.js'
15
-
16
- /**
17
- * @since 1.0.0
18
- * @category models
19
- */
20
- export interface BackingRunner<I, O> {
21
- readonly queue: Queue.Dequeue<readonly [portId: number, message: I]>
22
- readonly send: (portId: number, message: O, transfers?: ReadonlyArray<unknown>) => Effect.Effect<void>
23
- }
24
-
25
- /**
26
- * @since 1.0.0
27
- * @category models
28
- */
29
- export declare namespace BackingRunner {
30
- /**
31
- * @since 1.0.0
32
- * @category models
33
- */
34
- export type Message<I> = readonly [request: 0, I] | readonly [close: 1]
35
- }
36
-
37
- /**
38
- * @since 1.0.0
39
- * @category type ids
40
- */
41
- export const PlatformRunnerTypeId: unique symbol = internal.PlatformRunnerTypeId
42
-
43
- /**
44
- * @since 1.0.0
45
- * @category type ids
46
- */
47
- export type PlatformRunnerTypeId = typeof PlatformRunnerTypeId
48
-
49
- /**
50
- * @since 1.0.0
51
- * @category models
52
- */
53
- export interface PlatformRunner {
54
- readonly [PlatformRunnerTypeId]: PlatformRunnerTypeId
55
- readonly start: <I, O>(shutdown: Effect.Effect<void>) => Effect.Effect<BackingRunner<I, O>, WorkerError, Scope.Scope>
56
- }
57
-
58
- /**
59
- * @since 1.0.0
60
- * @category tags
61
- */
62
- export const PlatformRunner: Context.Tag<PlatformRunner, PlatformRunner> = internal.PlatformRunner
63
-
64
- /**
65
- * @since 1.0.0
66
- * @category models
67
- */
68
- export declare namespace Runner {
69
- /**
70
- * @since 1.0.0
71
- * @category models
72
- */
73
- export interface Options<I, O, E> {
74
- readonly decode?: (message: unknown) => Effect.Effect<I, WorkerError>
75
- readonly encodeOutput?: (request: I, message: O) => Effect.Effect<unknown, WorkerError>
76
- readonly encodeError?: (request: I, error: E) => Effect.Effect<unknown, WorkerError>
77
- readonly transfers?: (message: O | E) => ReadonlyArray<unknown>
78
- }
79
- }
80
-
81
- /**
82
- * @since 1.0.0
83
- * @category constructors
84
- */
85
- export const make: <I, E, R, O>(
86
- process: (request: I) => Stream.Stream<O, E, R> | Effect.Effect<O, E, R>,
87
- options?: Runner.Options<I, O, E> | undefined,
88
- ) => Effect.Effect<void, WorkerError, Scope.Scope | R | PlatformRunner> = internal.make
89
-
90
- /**
91
- * @since 1.0.0
92
- * @category layers
93
- */
94
- export const layer: <I, E, R, O>(
95
- process: (request: I) => Stream.Stream<O, E, R> | Effect.Effect<O, E, R>,
96
- options?: Runner.Options<I, O, E> | undefined,
97
- ) => Layer.Layer<never, WorkerError, R | PlatformRunner> = internal.layer
98
-
99
- /**
100
- * @since 1.0.0
101
- * @category models
102
- */
103
- export declare namespace SerializedRunner {
104
- /**
105
- * @since 1.0.0
106
- */
107
- export type Handlers<A extends Schema.TaggedRequest.All> = {
108
- readonly [K in A['_tag']]: Extract<A, { readonly _tag: K }> extends Serializable.SerializableWithResult<
109
- infer S,
110
- infer _SI,
111
- infer _SR,
112
- infer A,
113
- infer _AI,
114
- infer E,
115
- infer _EI,
116
- infer _RR
117
- >
118
- ? (
119
- _: S,
120
- ) => Stream.Stream<A, E, any> | Effect.Effect<A, E, any> | Layer.Layer<any, E, any> | Layer.Layer<never, E, any>
121
- : never
122
- }
123
-
124
- /**
125
- * @since 1.0.0
126
- */
127
- export type HandlersContext<Handlers extends Record<string, (...args: ReadonlyArray<any>) => any>> =
128
- | Exclude<
129
- {
130
- [K in keyof Handlers]: ReturnType<Handlers[K]> extends Stream.Stream<infer _A, infer _E, infer R> ? R : never
131
- }[keyof Handlers],
132
- InitialContext<Handlers>
133
- >
134
- | InitialEnv<Handlers>
135
-
136
- /**
137
- * @since 1.0.0
138
- */
139
- type InitialContext<Handlers extends Record<string, (...args: ReadonlyArray<any>) => any>> =
140
- Handlers['InitialMessage'] extends (...args: ReadonlyArray<any>) => Layer.Layer<infer A, infer _E, infer _R>
141
- ? A
142
- : never
143
-
144
- /**
145
- * @since 1.0.0
146
- */
147
- type InitialEnv<Handlers extends Record<string, (...args: ReadonlyArray<any>) => any>> =
148
- Handlers['InitialMessage'] extends (...args: ReadonlyArray<any>) => Layer.Layer<infer _A, infer _E, infer R>
149
- ? R
150
- : never
151
- }
152
-
153
- /**
154
- * @since 1.0.0
155
- * @category constructors
156
- */
157
- export const makeSerialized: <
158
- R,
159
- I,
160
- A extends Schema.TaggedRequest.All,
161
- const Handlers extends SerializedRunner.Handlers<A>,
162
- >(
163
- schema: Schema.Schema<A, I, R>,
164
- handlers: Handlers,
165
- ) => Effect.Effect<void, WorkerError, PlatformRunner | Scope.Scope | R | SerializedRunner.HandlersContext<Handlers>> =
166
- internal.makeSerialized
167
-
168
- /**
169
- * @since 1.0.0
170
- * @category layers
171
- */
172
- export const layerSerialized: <
173
- R,
174
- I,
175
- A extends Schema.TaggedRequest.All,
176
- const Handlers extends SerializedRunner.Handlers<A>,
177
- >(
178
- schema: Schema.Schema<A, I, R>,
179
- handlers: Handlers,
180
- ) => Layer.Layer<never, WorkerError, PlatformRunner | R | SerializedRunner.HandlersContext<Handlers>> =
181
- internal.layerSerialized
@@ -1,417 +0,0 @@
1
- /* eslint-disable prefer-arrow/prefer-arrow-functions */
2
- import { Transferable } from '@effect/platform'
3
- import * as Schema from '@effect/schema/Schema'
4
- import * as Serializable from '@effect/schema/Serializable'
5
- import * as Arr from 'effect/Array'
6
- import * as Cause from 'effect/Cause'
7
- import * as Channel from 'effect/Channel'
8
- import * as Chunk from 'effect/Chunk'
9
- import * as Context from 'effect/Context'
10
- import * as Deferred from 'effect/Deferred'
11
- import * as Effect from 'effect/Effect'
12
- import * as Exit from 'effect/Exit'
13
- import * as Fiber from 'effect/Fiber'
14
- import { identity, pipe } from 'effect/Function'
15
- import * as Layer from 'effect/Layer'
16
- import * as Option from 'effect/Option'
17
- import * as Pool from 'effect/Pool'
18
- import * as Queue from 'effect/Queue'
19
- import * as Schedule from 'effect/Schedule'
20
- import type * as Scope from 'effect/Scope'
21
- import * as Stream from 'effect/Stream'
22
- import * as Tracer from 'effect/Tracer'
23
-
24
- import type * as Worker from '../Worker.js'
25
- import { WorkerError } from '../WorkerError.js'
26
-
27
- /** @internal */
28
- export const defaultQueue = <I>() =>
29
- Effect.map(
30
- Queue.unbounded<readonly [id: number, item: I, span: Option.Option<Tracer.Span>]>(),
31
- (queue): Worker.WorkerQueue<I> => ({
32
- offer: (id, item, span) => Queue.offer(queue, [id, item, span]),
33
- take: Queue.take(queue),
34
- shutdown: Queue.shutdown(queue),
35
- }),
36
- )
37
-
38
- /** @internal */
39
- export const PlatformWorkerTypeId: Worker.PlatformWorkerTypeId = Symbol.for(
40
- '@effect/platform/Worker/PlatformWorker',
41
- ) as Worker.PlatformWorkerTypeId
42
-
43
- /** @internal */
44
- export const PlatformWorker = Context.GenericTag<Worker.PlatformWorker>('@effect/platform/Worker/PlatformWorker')
45
-
46
- /** @internal */
47
- export const WorkerManagerTypeId: Worker.WorkerManagerTypeId = Symbol.for(
48
- '@effect/platform/Worker/WorkerManager',
49
- ) as Worker.WorkerManagerTypeId
50
-
51
- /** @internal */
52
- export const WorkerManager = Context.GenericTag<Worker.WorkerManager>('@effect/platform/Worker/WorkerManager')
53
-
54
- /** @internal */
55
- export const Spawner = Context.GenericTag<Worker.Spawner, Worker.SpawnerFn>('@effect/platform/Worker/Spawner')
56
-
57
- /** @internal */
58
- export const makeManager = Effect.gen(function* () {
59
- const platform = yield* PlatformWorker
60
- let idCounter = 0
61
- return WorkerManager.of({
62
- [WorkerManagerTypeId]: WorkerManagerTypeId,
63
- spawn<I, O, E>({ encode, initialMessage, queue, transfers = (_) => [] }: Worker.Worker.Options<I>) {
64
- return Effect.gen(function* (_) {
65
- const spawn = yield* _(Spawner)
66
- const id = idCounter++
67
- let requestIdCounter = 0
68
- const requestMap = new Map<
69
- number,
70
- readonly [Queue.Queue<Exit.Exit<ReadonlyArray<O>, E | WorkerError>>, Deferred.Deferred<void>]
71
- >()
72
- const sendQueue = yield* Effect.acquireRelease(
73
- Queue.unbounded<readonly [message: Worker.Worker.Request, transfers?: ReadonlyArray<unknown>]>(),
74
- Queue.shutdown,
75
- )
76
-
77
- const collector = Transferable.unsafeMakeCollector()
78
- const wrappedEncode = encode
79
- ? (message: I) =>
80
- Effect.zipRight(
81
- collector.clear,
82
- Effect.provideService(encode(message), Transferable.Collector, collector),
83
- )
84
- : Effect.succeed
85
-
86
- const outbound = queue ?? (yield* defaultQueue<I>())
87
- yield* Effect.addFinalizer(() => outbound.shutdown)
88
-
89
- yield* Effect.gen(function* () {
90
- const readyLatch = yield* Deferred.make<void>()
91
- const backing = yield* platform.spawn<Worker.Worker.Request, Worker.Worker.Response<E, O>>(spawn(id))
92
- const send = pipe(
93
- sendQueue.take,
94
- Effect.flatMap(([message, transfers]) => backing.send(message, transfers)),
95
- Effect.forever,
96
- )
97
- const take = pipe(
98
- Queue.take(backing.queue),
99
- Effect.flatMap((msg) => {
100
- if (msg[0] === 0) {
101
- return Deferred.complete(readyLatch, Effect.void)
102
- }
103
- return handleMessage(msg[1])
104
- }),
105
- Effect.forever,
106
- )
107
- return yield* Effect.all(
108
- [Fiber.join(backing.fiber), Effect.zipRight(Deferred.await(readyLatch), send), take],
109
- { concurrency: 'unbounded' },
110
- )
111
- }).pipe(
112
- Effect.scoped,
113
- Effect.onError((cause) =>
114
- Effect.forEach(requestMap.values(), ([queue]) => Queue.offer(queue, Exit.failCause(cause))),
115
- ),
116
- Effect.retry(Schedule.spaced(1000)),
117
- Effect.annotateLogs({
118
- package: '@effect/platform',
119
- module: 'Worker',
120
- }),
121
- Effect.interruptible,
122
- Effect.forkScoped,
123
- )
124
-
125
- yield* Effect.addFinalizer(() =>
126
- Effect.zipRight(
127
- Effect.forEach(requestMap.values(), ([queue]) => Queue.offer(queue, Exit.failCause(Cause.empty)), {
128
- discard: true,
129
- }),
130
- Effect.sync(() => requestMap.clear()),
131
- ),
132
- )
133
-
134
- const handleMessage = (response: Worker.Worker.Response<E, O>) =>
135
- Effect.suspend(() => {
136
- const queue = requestMap.get(response[0])
137
- if (!queue) return Effect.void
138
-
139
- switch (response[1]) {
140
- // data
141
- case 0: {
142
- return Queue.offer(queue[0], Exit.succeed(response[2]))
143
- }
144
- // end
145
- case 1: {
146
- return response.length === 2
147
- ? Queue.offer(queue[0], Exit.failCause(Cause.empty))
148
- : Effect.zipRight(
149
- Queue.offer(queue[0], Exit.succeed(response[2])),
150
- Queue.offer(queue[0], Exit.failCause(Cause.empty)),
151
- )
152
- }
153
- // error / defect
154
- case 2:
155
- case 3: {
156
- return Queue.offer(
157
- queue[0],
158
- response[1] === 2
159
- ? Exit.fail(response[2])
160
- : Exit.failCause(WorkerError.decodeCause(response[2] as any)),
161
- )
162
- }
163
- }
164
- })
165
-
166
- const executeAcquire = (request: I) =>
167
- Effect.tap(
168
- Effect.all([
169
- Effect.sync(() => requestIdCounter++),
170
- Queue.unbounded<Exit.Exit<ReadonlyArray<O>, E | WorkerError>>(),
171
- Deferred.make<void>(),
172
- Effect.map(
173
- Effect.serviceOption(Tracer.ParentSpan),
174
- Option.filter((span): span is Tracer.Span => span._tag === 'Span'),
175
- ),
176
- ]),
177
- ([id, queue, deferred, span]) =>
178
- Effect.suspend(() => {
179
- requestMap.set(id, [queue, deferred])
180
- return outbound.offer(id, request, span)
181
- }),
182
- )
183
-
184
- const executeRelease = (
185
- [id, , deferred]: [
186
- number,
187
- Queue.Queue<Exit.Exit<ReadonlyArray<O>, E | WorkerError>>,
188
- Deferred.Deferred<void>,
189
- Option.Option<Tracer.Span>,
190
- ],
191
- exit: Exit.Exit<unknown, unknown>,
192
- ) => {
193
- const release = Effect.zipRight(
194
- Deferred.complete(deferred, Effect.void),
195
- Effect.sync(() => requestMap.delete(id)),
196
- )
197
- return Exit.isFailure(exit) ? Effect.zipRight(sendQueue.offer([[id, 1]]), release) : release
198
- }
199
-
200
- const execute = (request: I) =>
201
- Stream.flatMap(Stream.acquireRelease(executeAcquire(request), executeRelease), ([, queue]) => {
202
- const loop: Channel.Channel<
203
- Chunk.Chunk<O>,
204
- unknown,
205
- E | WorkerError,
206
- unknown,
207
- void,
208
- unknown
209
- > = Channel.flatMap(
210
- Queue.take(queue),
211
- Exit.match({
212
- onFailure: (cause) => (Cause.isEmpty(cause) ? Channel.void : Channel.failCause(cause)),
213
- onSuccess: (value) => Channel.flatMap(Channel.write(Chunk.unsafeFromArray(value)), () => loop),
214
- }),
215
- )
216
- return Stream.fromChannel(loop)
217
- })
218
-
219
- const executeEffect = (request: I) =>
220
- Effect.acquireUseRelease(
221
- executeAcquire(request),
222
- ([, queue]) => Effect.flatMap(Queue.take(queue), Exit.map(Arr.unsafeGet(0))),
223
- executeRelease,
224
- )
225
-
226
- yield* outbound.take.pipe(
227
- Effect.flatMap(([id, request, span]) =>
228
- Effect.fork(
229
- Effect.suspend(() => {
230
- const result = requestMap.get(id)
231
- if (!result) return Effect.void
232
- const transferables = transfers(request)
233
- const spanTuple = Option.getOrUndefined(
234
- Option.map(span, (span) => [span.traceId, span.spanId, span.sampled] as const),
235
- )
236
- return pipe(
237
- Effect.flatMap(wrappedEncode(request), (payload) =>
238
- sendQueue.offer([
239
- [id, 0, payload, spanTuple],
240
- [...transferables, ...collector.unsafeRead()],
241
- ]),
242
- ),
243
- Effect.catchAllCause((cause) => Queue.offer(result[0], Exit.failCause(cause))),
244
- Effect.zipRight(Deferred.await(result[1])),
245
- )
246
- }),
247
- ),
248
- ),
249
- Effect.forever,
250
- Effect.forkScoped,
251
- Effect.interruptible,
252
- )
253
-
254
- if (initialMessage) {
255
- yield* Effect.sync(initialMessage).pipe(
256
- Effect.flatMap(executeEffect),
257
- Effect.mapError((error) => new WorkerError({ reason: 'spawn', error })),
258
- )
259
- }
260
-
261
- return { id, execute, executeEffect }
262
- }).pipe(Effect.parallelFinalizers)
263
- },
264
- })
265
- })
266
-
267
- /** @internal */
268
- export const layerManager = Layer.effect(WorkerManager, makeManager)
269
-
270
- /** @internal */
271
- export const makePool = <I, O, E>(options: Worker.WorkerPool.Options<I>) =>
272
- Effect.gen(function* () {
273
- const manager = yield* WorkerManager
274
- const workers = new Set<Worker.Worker<I, O, E>>()
275
- const acquire = pipe(
276
- manager.spawn<I, O, E>(options),
277
- Effect.tap((worker) => Effect.sync(() => workers.add(worker))),
278
- Effect.tap((worker) => Effect.addFinalizer(() => Effect.sync(() => workers.delete(worker)))),
279
- options.onCreate ? Effect.tap(options.onCreate) : identity,
280
- )
281
- const backing =
282
- 'minSize' in options
283
- ? yield* Pool.makeWithTTL({
284
- acquire,
285
- min: options.minSize,
286
- max: options.maxSize,
287
- concurrency: options.concurrency,
288
- targetUtilization: options.targetUtilization,
289
- timeToLive: options.timeToLive,
290
- })
291
- : yield* Pool.make({
292
- acquire,
293
- size: options.size,
294
- concurrency: options.concurrency,
295
- targetUtilization: options.targetUtilization,
296
- })
297
- const pool: Worker.WorkerPool<I, O, E> = {
298
- backing,
299
- broadcast: (message: I) =>
300
- Effect.forEach(workers, (worker) => worker.executeEffect(message), {
301
- concurrency: 'unbounded',
302
- discard: true,
303
- }),
304
- execute: (message: I) => Stream.unwrapScoped(Effect.map(backing.get, (worker) => worker.execute(message))),
305
- executeEffect: (message: I) =>
306
- Effect.scoped(Effect.flatMap(backing.get, (worker) => worker.executeEffect(message))),
307
- }
308
-
309
- // report any spawn errors
310
- yield* Effect.scoped(backing.get)
311
-
312
- return pool
313
- })
314
-
315
- /** @internal */
316
- export const makePoolLayer = <Tag, I, O, E>(
317
- tag: Context.Tag<Tag, Worker.WorkerPool<I, O, E>>,
318
- options: Worker.WorkerPool.Options<I>,
319
- ) => Layer.scoped(tag, makePool(options))
320
-
321
- /** @internal */
322
- export const makeSerialized = <I extends Schema.TaggedRequest.All>(
323
- options: Worker.SerializedWorker.Options<I>,
324
- ): Effect.Effect<Worker.SerializedWorker<I>, WorkerError, Worker.WorkerManager | Worker.Spawner | Scope.Scope> =>
325
- Effect.gen(function* () {
326
- const manager = yield* WorkerManager
327
- const backing = yield* manager.spawn({
328
- ...(options as any),
329
- encode(message) {
330
- return Effect.mapError(
331
- Serializable.serialize(message as any),
332
- (error) => new WorkerError({ reason: 'encode', error }),
333
- )
334
- },
335
- })
336
- const execute = <Req extends I>(message: Req) => {
337
- const parseSuccess = Schema.decode(Serializable.successSchema(message as any))
338
- const parseFailure = Schema.decode(Serializable.failureSchema(message as any))
339
- return pipe(
340
- backing.execute(message),
341
- Stream.catchAll((error) => Effect.flatMap(parseFailure(error), Effect.fail)),
342
- Stream.mapEffect(parseSuccess),
343
- )
344
- }
345
- const executeEffect = <Req extends I>(message: Req) => {
346
- const parseSuccess = Schema.decode(Serializable.successSchema(message as any))
347
- const parseFailure = Schema.decode(Serializable.failureSchema(message as any))
348
- return Effect.matchEffect(backing.executeEffect(message), {
349
- onFailure: (error) => Effect.flatMap(parseFailure(error), Effect.fail),
350
- onSuccess: parseSuccess,
351
- })
352
- }
353
- return identity<Worker.SerializedWorker<I>>({
354
- id: backing.id,
355
- execute: execute as any,
356
- executeEffect: executeEffect as any,
357
- })
358
- })
359
-
360
- /** @internal */
361
- export const makePoolSerialized = <I extends Schema.TaggedRequest.All>(
362
- options: Worker.SerializedWorkerPool.Options<I>,
363
- ) =>
364
- Effect.gen(function* () {
365
- const manager = yield* WorkerManager
366
- const workers = new Set<Worker.SerializedWorker<I>>()
367
- const acquire = pipe(
368
- makeSerialized<I>(options),
369
- Effect.tap((worker) => Effect.sync(() => workers.add(worker))),
370
- Effect.tap((worker) => Effect.addFinalizer(() => Effect.sync(() => workers.delete(worker)))),
371
- options.onCreate
372
- ? Effect.tap(options.onCreate as (worker: Worker.SerializedWorker<I>) => Effect.Effect<void, WorkerError>)
373
- : identity,
374
- Effect.provideService(WorkerManager, manager),
375
- )
376
- const backing = yield* 'timeToLive' in options
377
- ? Pool.makeWithTTL({
378
- acquire,
379
- min: options.minSize,
380
- max: options.maxSize,
381
- concurrency: options.concurrency,
382
- targetUtilization: options.targetUtilization,
383
- timeToLive: options.timeToLive,
384
- })
385
- : Pool.make({
386
- acquire,
387
- size: options.size,
388
- concurrency: options.concurrency,
389
- targetUtilization: options.targetUtilization,
390
- })
391
- const pool: Worker.SerializedWorkerPool<I> = {
392
- backing,
393
- broadcast: <Req extends I>(message: Req) =>
394
- Effect.forEach(workers, (worker) => worker.executeEffect(message), {
395
- concurrency: 'unbounded',
396
- discard: true,
397
- }) as any,
398
- execute: <Req extends I>(message: Req) =>
399
- Stream.unwrapScoped(Effect.map(backing.get, (worker) => worker.execute(message))) as any,
400
- executeEffect: <Req extends I>(message: Req) =>
401
- Effect.scoped(Effect.flatMap(backing.get, (worker) => worker.executeEffect(message))) as any,
402
- }
403
-
404
- // report any spawn errors
405
- yield* Effect.scoped(backing.get)
406
-
407
- return pool
408
- })
409
-
410
- /** @internal */
411
- export const makePoolSerializedLayer = <Tag, I extends Schema.TaggedRequest.All>(
412
- tag: Context.Tag<Tag, Worker.SerializedWorkerPool<I>>,
413
- options: Worker.SerializedWorkerPool.Options<I>,
414
- ) => Layer.scoped(tag, makePoolSerialized(options))
415
-
416
- /** @internal */
417
- export const layerSpawner = <W = unknown>(spawner: Worker.SpawnerFn<W>) => Layer.succeed(Spawner, spawner)
@@ -1,6 +0,0 @@
1
- import type * as WorkerError_ from '../WorkerError.js'
2
-
3
- /** @internal */
4
- export const WorkerErrorTypeId: WorkerError_.WorkerErrorTypeId = Symbol.for(
5
- '@effect/platform/WorkerError',
6
- ) as WorkerError_.WorkerErrorTypeId