@effect/platform 0.22.0 → 0.23.0

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 (50) hide show
  1. package/Worker/dist/effect-platform-Worker.cjs.d.mts +2 -0
  2. package/Worker/dist/effect-platform-Worker.cjs.d.mts.map +1 -0
  3. package/Worker/dist/effect-platform-Worker.cjs.d.ts +2 -0
  4. package/Worker/dist/effect-platform-Worker.cjs.d.ts.map +1 -0
  5. package/Worker/dist/effect-platform-Worker.cjs.dev.js +291 -0
  6. package/Worker/dist/effect-platform-Worker.cjs.js +7 -0
  7. package/Worker/dist/effect-platform-Worker.cjs.mjs +10 -0
  8. package/Worker/dist/effect-platform-Worker.cjs.prod.js +291 -0
  9. package/Worker/dist/effect-platform-Worker.esm.js +252 -0
  10. package/Worker/package.json +4 -0
  11. package/WorkerError/dist/effect-platform-WorkerError.cjs.d.mts +2 -0
  12. package/WorkerError/dist/effect-platform-WorkerError.cjs.d.mts.map +1 -0
  13. package/WorkerError/dist/effect-platform-WorkerError.cjs.d.ts +2 -0
  14. package/WorkerError/dist/effect-platform-WorkerError.cjs.d.ts.map +1 -0
  15. package/WorkerError/dist/effect-platform-WorkerError.cjs.dev.js +65 -0
  16. package/WorkerError/dist/effect-platform-WorkerError.cjs.js +7 -0
  17. package/WorkerError/dist/effect-platform-WorkerError.cjs.mjs +4 -0
  18. package/WorkerError/dist/effect-platform-WorkerError.cjs.prod.js +65 -0
  19. package/WorkerError/dist/effect-platform-WorkerError.esm.js +40 -0
  20. package/WorkerError/package.json +4 -0
  21. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.d.mts +2 -0
  22. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.d.mts.map +1 -0
  23. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.d.ts +2 -0
  24. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.d.ts.map +1 -0
  25. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.dev.js +129 -0
  26. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.js +7 -0
  27. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.mjs +5 -0
  28. package/WorkerRunner/dist/effect-platform-WorkerRunner.cjs.prod.js +129 -0
  29. package/WorkerRunner/dist/effect-platform-WorkerRunner.esm.js +97 -0
  30. package/WorkerRunner/package.json +4 -0
  31. package/dist/declarations/src/Worker.d.ts +170 -0
  32. package/dist/declarations/src/Worker.d.ts.map +1 -0
  33. package/dist/declarations/src/WorkerError.d.ts +30 -0
  34. package/dist/declarations/src/WorkerError.d.ts.map +1 -0
  35. package/dist/declarations/src/WorkerRunner.d.ts +72 -0
  36. package/dist/declarations/src/WorkerRunner.d.ts.map +1 -0
  37. package/dist/declarations/src/index.d.ts +12 -0
  38. package/dist/declarations/src/index.d.ts.map +1 -1
  39. package/dist/effect-platform.cjs.dev.js +9 -0
  40. package/dist/effect-platform.cjs.mjs +4 -1
  41. package/dist/effect-platform.cjs.prod.js +9 -0
  42. package/dist/effect-platform.esm.js +6 -0
  43. package/package.json +27 -6
  44. package/src/Worker.ts +207 -0
  45. package/src/WorkerError.ts +34 -0
  46. package/src/WorkerRunner.ts +83 -0
  47. package/src/index.ts +15 -0
  48. package/src/internal/worker.ts +262 -0
  49. package/src/internal/workerError.ts +16 -0
  50. package/src/internal/workerRunner.ts +83 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/platform",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "Unified interfaces for common platform-specific services",
5
5
  "main": "dist/effect-platform.cjs.js",
6
6
  "module": "dist/effect-platform.esm.js",
@@ -34,13 +34,13 @@
34
34
  "path-browserify": "^1.0.1"
35
35
  },
36
36
  "devDependencies": {
37
- "@effect/schema": "^0.43.0",
37
+ "@effect/schema": "^0.44.0",
38
38
  "@types/path-browserify": "^1.0.0",
39
- "effect": "2.0.0-next.48"
39
+ "effect": "2.0.0-next.49"
40
40
  },
41
41
  "peerDependencies": {
42
- "@effect/schema": "^0.43.0",
43
- "effect": "2.0.0-next.48"
42
+ "@effect/schema": "^0.44.0",
43
+ "effect": "2.0.0-next.49"
44
44
  },
45
45
  "files": [
46
46
  "src",
@@ -55,7 +55,10 @@
55
55
  "HttpServer",
56
56
  "KeyValueStore",
57
57
  "Path",
58
- "Runtime"
58
+ "Runtime",
59
+ "Worker",
60
+ "WorkerError",
61
+ "WorkerRunner"
59
62
  ],
60
63
  "exports": {
61
64
  ".": {
@@ -238,6 +241,24 @@
238
241
  "module": "./Runtime/dist/effect-platform-Runtime.esm.js",
239
242
  "import": "./Runtime/dist/effect-platform-Runtime.cjs.mjs",
240
243
  "default": "./Runtime/dist/effect-platform-Runtime.cjs.js"
244
+ },
245
+ "./Worker": {
246
+ "types": "./dist/declarations/src/Worker.d.ts",
247
+ "module": "./Worker/dist/effect-platform-Worker.esm.js",
248
+ "import": "./Worker/dist/effect-platform-Worker.cjs.mjs",
249
+ "default": "./Worker/dist/effect-platform-Worker.cjs.js"
250
+ },
251
+ "./WorkerError": {
252
+ "types": "./dist/declarations/src/WorkerError.d.ts",
253
+ "module": "./WorkerError/dist/effect-platform-WorkerError.esm.js",
254
+ "import": "./WorkerError/dist/effect-platform-WorkerError.cjs.mjs",
255
+ "default": "./WorkerError/dist/effect-platform-WorkerError.cjs.js"
256
+ },
257
+ "./WorkerRunner": {
258
+ "types": "./dist/declarations/src/WorkerRunner.d.ts",
259
+ "module": "./WorkerRunner/dist/effect-platform-WorkerRunner.esm.js",
260
+ "import": "./WorkerRunner/dist/effect-platform-WorkerRunner.cjs.mjs",
261
+ "default": "./WorkerRunner/dist/effect-platform-WorkerRunner.cjs.js"
241
262
  }
242
263
  },
243
264
  "scripts": {
package/src/Worker.ts ADDED
@@ -0,0 +1,207 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import type { Effect } from "effect"
5
+ import type * as Context from "effect/Context"
6
+ import type * as Duration from "effect/Duration"
7
+ import type * as Layer from "effect/Layer"
8
+ import type * as Pool from "effect/Pool"
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
+ import * as internal from "./internal/worker"
13
+ import type { WorkerError } from "./WorkerError"
14
+
15
+ /**
16
+ * @since 1.0.0
17
+ * @category models
18
+ */
19
+ export interface BackingWorker<I, O> {
20
+ readonly join: Effect.Effect<never, WorkerError, never>
21
+ readonly send: (message: I, transfers?: ReadonlyArray<unknown>) => Effect.Effect<never, never, void>
22
+ readonly queue: Queue.Dequeue<BackingWorker.Message<O>>
23
+ }
24
+
25
+ /**
26
+ * @since 1.0.0
27
+ * @category models
28
+ */
29
+ export declare namespace BackingWorker {
30
+ /**
31
+ * @since 1.0.0
32
+ * @category models
33
+ */
34
+ export type Message<O> = readonly [ready: 0] | readonly [data: 1, O]
35
+ }
36
+
37
+ /**
38
+ * @since 1.0.0
39
+ * @category type ids
40
+ */
41
+ export const PlatformWorkerTypeId: unique symbol = internal.PlatformWorkerTypeId
42
+
43
+ /**
44
+ * @since 1.0.0
45
+ * @category type ids
46
+ */
47
+ export type PlatformWorkerTypeId = typeof PlatformWorkerTypeId
48
+
49
+ /**
50
+ * @since 1.0.0
51
+ * @category models
52
+ */
53
+ export interface PlatformWorker {
54
+ readonly [PlatformWorkerTypeId]: PlatformWorkerTypeId
55
+ readonly spawn: <I, O>(worker: unknown) => Effect.Effect<Scope.Scope, WorkerError, BackingWorker<I, O>>
56
+ }
57
+
58
+ /**
59
+ * @since 1.0.0
60
+ * @category tags
61
+ */
62
+ export const PlatformWorker: Context.Tag<PlatformWorker, PlatformWorker> = internal.PlatformWorker
63
+
64
+ /**
65
+ * @since 1.0.0
66
+ * @category models
67
+ */
68
+ export interface Worker<I, E, O> {
69
+ readonly id: number
70
+ readonly join: Effect.Effect<never, WorkerError, never>
71
+ readonly execute: (message: I) => Stream.Stream<never, E, O>
72
+ readonly executeEffect: (message: I) => Effect.Effect<never, E, O>
73
+ }
74
+
75
+ /**
76
+ * @since 1.0.0
77
+ * @category models
78
+ */
79
+ export declare namespace Worker {
80
+ /**
81
+ * @since 1.0.0
82
+ * @category models
83
+ */
84
+ export interface Options<I, W = unknown> {
85
+ readonly spawn: (id: number) => W
86
+ readonly transfers?: (message: I) => ReadonlyArray<unknown>
87
+ readonly permits?: number
88
+ readonly queue?: WorkerQueue<I>
89
+ }
90
+
91
+ /**
92
+ * @since 1.0.0
93
+ * @category models
94
+ */
95
+ export type Request<I> = readonly [id: number, data: 0, I] | readonly [id: number, interrupt: 1]
96
+
97
+ /**
98
+ * @since 1.0.0
99
+ * @category models
100
+ */
101
+ export type Response<E, O> =
102
+ | readonly [id: number, data: 0, O]
103
+ | readonly [id: number, end: 1]
104
+ | readonly [id: number, end: 1, O]
105
+ | readonly [id: number, error: 2, E]
106
+ | readonly [id: number, defect: 3, unknown]
107
+ }
108
+
109
+ /**
110
+ * @since 1.0.0
111
+ * @category models
112
+ */
113
+ export interface WorkerPool<I, E, O> {
114
+ readonly backing: Pool.Pool<WorkerError, Worker<I, E, O>>
115
+ readonly execute: (message: I) => Stream.Stream<never, E | WorkerError, O>
116
+ readonly executeEffect: (message: I) => Effect.Effect<never, E | WorkerError, O>
117
+ }
118
+
119
+ /**
120
+ * @since 1.0.0
121
+ * @category models
122
+ */
123
+ export declare namespace WorkerPool {
124
+ /**
125
+ * @since 1.0.0
126
+ * @category models
127
+ */
128
+ export type Options<I, W = unknown> =
129
+ & Worker.Options<I, W>
130
+ & ({
131
+ readonly size: number
132
+ } | {
133
+ readonly minSize: number
134
+ readonly maxSize: number
135
+ readonly timeToLive: Duration.DurationInput
136
+ })
137
+ }
138
+
139
+ /**
140
+ * @category models
141
+ * @since 1.0.0
142
+ */
143
+ export interface WorkerQueue<I> {
144
+ readonly offer: (id: number, item: I) => Effect.Effect<never, never, void>
145
+ readonly take: Effect.Effect<never, never, readonly [id: number, item: I]>
146
+ readonly shutdown: Effect.Effect<never, never, void>
147
+ }
148
+
149
+ /**
150
+ * @since 1.0.0
151
+ * @category type ids
152
+ */
153
+ export const WorkerManagerTypeId: unique symbol = internal.WorkerManagerTypeId
154
+
155
+ /**
156
+ * @since 1.0.0
157
+ * @category type ids
158
+ */
159
+ export type WorkerManagerTypeId = typeof WorkerManagerTypeId
160
+
161
+ /**
162
+ * @since 1.0.0
163
+ * @category models
164
+ */
165
+ export interface WorkerManager {
166
+ readonly [WorkerManagerTypeId]: WorkerManagerTypeId
167
+ readonly spawn: <I, E, O>(
168
+ options: Worker.Options<I>
169
+ ) => Effect.Effect<Scope.Scope, WorkerError, Worker<I, E, O>>
170
+ }
171
+
172
+ /**
173
+ * @since 1.0.0
174
+ * @category tags
175
+ */
176
+ export const WorkerManager: Context.Tag<WorkerManager, WorkerManager> = internal.WorkerManager
177
+
178
+ /**
179
+ * @since 1.0.0
180
+ * @category constructors
181
+ */
182
+ export const makeManager: Effect.Effect<PlatformWorker, never, WorkerManager> = internal.makeManager
183
+
184
+ /**
185
+ * @since 1.0.0
186
+ * @category layers
187
+ */
188
+ export const layerManager: Layer.Layer<PlatformWorker, never, WorkerManager> = internal.layerManager
189
+
190
+ /**
191
+ * @since 1.0.0
192
+ * @category constructors
193
+ */
194
+ export const makePool: <W>() => <I, E, O>(
195
+ options: WorkerPool.Options<I, W>
196
+ ) => Effect.Effect<WorkerManager | Scope.Scope, never, WorkerPool<I, E, O>> = internal.makePool
197
+
198
+ /**
199
+ * @since 1.0.0
200
+ * @category constructors
201
+ */
202
+ export const makePoolLayer: <W>(
203
+ managerLayer: Layer.Layer<never, never, WorkerManager>
204
+ ) => <Tag, I, E, O>(
205
+ tag: Context.Tag<Tag, WorkerPool<I, E, O>>,
206
+ options: WorkerPool.Options<I, W>
207
+ ) => Layer.Layer<never, never, Tag> = internal.makePoolLayer
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import type * as Data from "effect/Data"
5
+ import * as internal from "./internal/workerError"
6
+
7
+ /**
8
+ * @since 1.0.0
9
+ * @category type ids
10
+ */
11
+ export const WorkerErrorTypeId: unique symbol = internal.WorkerErrorTypeId
12
+
13
+ /**
14
+ * @since 1.0.0
15
+ * @category type ids
16
+ */
17
+ export type WorkerErrorTypeId = typeof WorkerErrorTypeId
18
+
19
+ /**
20
+ * @since 1.0.0
21
+ * @category errors
22
+ */
23
+ export interface WorkerError extends Data.Case {
24
+ readonly [WorkerErrorTypeId]: WorkerErrorTypeId
25
+ readonly _tag: "WorkerError"
26
+ readonly reason: "spawn" | "decode" | "unknown"
27
+ readonly error: unknown
28
+ }
29
+
30
+ /**
31
+ * @since 1.0.0
32
+ * @category errors
33
+ */
34
+ export const WorkerError: (reason: "spawn" | "decode" | "unknown", error: unknown) => WorkerError = internal.WorkerError
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import type { Effect } from "effect"
5
+ import type * as Context from "effect/Context"
6
+ import type * as Fiber from "effect/Fiber"
7
+ import type * as Queue from "effect/Queue"
8
+ import type * as Scope from "effect/Scope"
9
+ import type * as Stream from "effect/Stream"
10
+ import * as internal from "./internal/workerRunner"
11
+ import type { WorkerError } from "./WorkerError"
12
+
13
+ /**
14
+ * @since 1.0.0
15
+ * @category models
16
+ */
17
+ export interface BackingRunner<I, O> {
18
+ readonly fiber: Fiber.Fiber<WorkerError, void>
19
+ readonly queue: Queue.Dequeue<I>
20
+ readonly send: (message: O, transfers?: ReadonlyArray<unknown>) => Effect.Effect<never, never, void>
21
+ }
22
+
23
+ /**
24
+ * @since 1.0.0
25
+ * @category models
26
+ */
27
+ export declare namespace BackingRunner {
28
+ /**
29
+ * @since 1.0.0
30
+ * @category models
31
+ */
32
+ export type Message<I> = readonly [request: 0, I] | readonly [close: 1]
33
+ }
34
+
35
+ /**
36
+ * @since 1.0.0
37
+ * @category type ids
38
+ */
39
+ export const PlatformRunnerTypeId: unique symbol = internal.PlatformRunnerTypeId
40
+
41
+ /**
42
+ * @since 1.0.0
43
+ * @category type ids
44
+ */
45
+ export type PlatformRunnerTypeId = typeof PlatformRunnerTypeId
46
+
47
+ /**
48
+ * @since 1.0.0
49
+ * @category models
50
+ */
51
+ export interface PlatformRunner {
52
+ readonly [PlatformRunnerTypeId]: PlatformRunnerTypeId
53
+ readonly start: <I, O>() => Effect.Effect<Scope.Scope, WorkerError, BackingRunner<I, O>>
54
+ }
55
+
56
+ /**
57
+ * @since 1.0.0
58
+ * @category tags
59
+ */
60
+ export const PlatformRunner: Context.Tag<PlatformRunner, PlatformRunner> = internal.PlatformRunner
61
+
62
+ /**
63
+ * @since 1.0.0
64
+ * @category models
65
+ */
66
+ export declare namespace Runner {
67
+ /**
68
+ * @since 1.0.0
69
+ * @category models
70
+ */
71
+ export interface Options<O> {
72
+ readonly transfers?: (message: O) => ReadonlyArray<unknown>
73
+ }
74
+ }
75
+
76
+ /**
77
+ * @since 1.0.0
78
+ * @category constructors
79
+ */
80
+ export const make: <I, R, E, O>(
81
+ process: (request: I) => Stream.Stream<R, E, O> | Effect.Effect<R, E, O>,
82
+ options?: Runner.Options<O> | undefined
83
+ ) => Effect.Effect<Scope.Scope | R | PlatformRunner, WorkerError, void> = internal.make
package/src/index.ts CHANGED
@@ -47,3 +47,18 @@ export * as Path from "@effect/platform/Path"
47
47
  * @since 1.0.0
48
48
  */
49
49
  export * as Runtime from "@effect/platform/Runtime"
50
+
51
+ /**
52
+ * @since 1.0.0
53
+ */
54
+ export * as Worker from "@effect/platform/Worker"
55
+
56
+ /**
57
+ * @since 1.0.0
58
+ */
59
+ export * as WorkerError from "@effect/platform/WorkerError"
60
+
61
+ /**
62
+ * @since 1.0.0
63
+ */
64
+ export * as WorkerRunner from "@effect/platform/WorkerRunner"
@@ -0,0 +1,262 @@
1
+ import * as Context from "effect/Context"
2
+ import * as Deferred from "effect/Deferred"
3
+ import * as Effect from "effect/Effect"
4
+ import * as Exit from "effect/Exit"
5
+ import * as Fiber from "effect/Fiber"
6
+ import { pipe } from "effect/Function"
7
+ import * as Layer from "effect/Layer"
8
+ import * as Pool from "effect/Pool"
9
+ import * as Queue from "effect/Queue"
10
+ import * as Stream from "effect/Stream"
11
+ import type * as Worker from "../Worker"
12
+ import type { WorkerError } from "../WorkerError"
13
+
14
+ /** @internal */
15
+ export const defaultQueue = <I>() =>
16
+ Effect.map(
17
+ Queue.unbounded<readonly [id: number, item: I]>(),
18
+ (queue): Worker.WorkerQueue<I> => ({
19
+ offer: (id, item) => Queue.offer(queue, [id, item]),
20
+ take: Queue.take(queue),
21
+ shutdown: Queue.shutdown(queue)
22
+ })
23
+ )
24
+
25
+ /** @internal */
26
+ export const PlatformWorkerTypeId: Worker.PlatformWorkerTypeId = Symbol.for(
27
+ "@effect/platform/Worker/PlatformWorker"
28
+ ) as Worker.PlatformWorkerTypeId
29
+
30
+ /** @internal */
31
+ export const PlatformWorker = Context.Tag<Worker.PlatformWorker>(
32
+ PlatformWorkerTypeId
33
+ )
34
+
35
+ /** @internal */
36
+ export const WorkerManagerTypeId: Worker.WorkerManagerTypeId = Symbol.for(
37
+ "@effect/platform/Worker/WorkerManager"
38
+ ) as Worker.WorkerManagerTypeId
39
+
40
+ /** @internal */
41
+ export const WorkerManager = Context.Tag<Worker.WorkerManager>(
42
+ WorkerManagerTypeId
43
+ )
44
+
45
+ /** @internal */
46
+ export const makeManager = Effect.gen(function*(_) {
47
+ const platform = yield* _(PlatformWorker)
48
+ let idCounter = 0
49
+ return WorkerManager.of({
50
+ [WorkerManagerTypeId]: WorkerManagerTypeId,
51
+ spawn<I, E, O>({ permits = 1, queue, spawn, transfers = (_) => [] }: Worker.Worker.Options<I>) {
52
+ return Effect.gen(function*(_) {
53
+ const id = idCounter++
54
+ const fiberId = yield* _(Effect.fiberId)
55
+ let requestIdCounter = 0
56
+ const readyLatch = yield* _(Deferred.make<never, void>())
57
+ const semaphore = yield* _(Effect.makeSemaphore(permits))
58
+ const requestMap = new Map<number, readonly [Queue.Queue<Exit.Exit<E, O>>, Deferred.Deferred<never, void>]>()
59
+
60
+ const outbound = queue ?? (yield* _(defaultQueue<I>()))
61
+ yield* _(Effect.addFinalizer(() => outbound.shutdown))
62
+
63
+ const backing = yield* _(
64
+ platform.spawn<Worker.Worker.Request<I>, Worker.Worker.Response<E, O>>(spawn(id))
65
+ )
66
+
67
+ yield* _(Effect.addFinalizer(() =>
68
+ Effect.zipRight(
69
+ Effect.forEach(requestMap.values(), ([queue]) => Queue.shutdown(queue), { discard: true }),
70
+ Effect.sync(() => requestMap.clear())
71
+ )
72
+ ))
73
+
74
+ const handleMessage = (msg: Worker.BackingWorker.Message<Worker.Worker.Response<E, O>>) =>
75
+ Effect.suspend(() => {
76
+ switch (msg[0]) {
77
+ case 0: {
78
+ return Deferred.complete(readyLatch, Effect.unit)
79
+ }
80
+ case 1: {
81
+ const response = msg[1]
82
+ const queue = requestMap.get(response[0])
83
+ if (!queue) return Effect.unit
84
+
85
+ switch (response[1]) {
86
+ // data
87
+ case 0: {
88
+ return Queue.offer(queue[0], Exit.succeed(response[2]))
89
+ }
90
+ // end
91
+ case 1: {
92
+ return response.length === 2 ?
93
+ Queue.shutdown(queue[0]) :
94
+ Effect.zipRight(
95
+ Queue.offer(queue[0], Exit.succeed(response[2])),
96
+ Queue.shutdown(queue[0])
97
+ )
98
+ }
99
+ // error / defect
100
+ case 2:
101
+ case 3: {
102
+ return Effect.zipRight(
103
+ Queue.offer(
104
+ queue[0],
105
+ response[1] === 2
106
+ ? Exit.fail(response[2])
107
+ : Exit.die(response[2])
108
+ ),
109
+ Queue.shutdown(queue[0])
110
+ )
111
+ }
112
+ }
113
+ }
114
+ }
115
+ })
116
+
117
+ const executeAcquire = (request: I) =>
118
+ Effect.tap(
119
+ Effect.all([
120
+ Effect.sync(() => requestIdCounter++),
121
+ Queue.unbounded<Exit.Exit<E, O>>(),
122
+ Deferred.make<never, void>()
123
+ ]),
124
+ ([id, queue, deferred]) =>
125
+ Effect.suspend(() => {
126
+ requestMap.set(id, [queue, deferred])
127
+ return outbound.offer(id, request)
128
+ })
129
+ )
130
+
131
+ const executeRelease = (
132
+ [id, , deferred]: [number, Queue.Queue<Exit.Exit<E, O>>, Deferred.Deferred<never, void>],
133
+ exit: Exit.Exit<unknown, unknown>
134
+ ) => {
135
+ const release = Effect.zipRight(
136
+ Deferred.complete(deferred, Effect.unit),
137
+ Effect.sync(() => requestMap.delete(id))
138
+ )
139
+ return Exit.isInterrupted(exit) ?
140
+ Effect.zipRight(
141
+ backing.send([id, 1]),
142
+ release
143
+ ) :
144
+ release
145
+ }
146
+
147
+ const execute = (request: I) =>
148
+ Stream.flatMap(
149
+ Stream.acquireRelease(
150
+ executeAcquire(request),
151
+ executeRelease
152
+ ),
153
+ ([, queue]) => Stream.flatten(Stream.fromQueue(queue))
154
+ )
155
+
156
+ const executeEffect = (request: I) =>
157
+ Effect.acquireUseRelease(
158
+ executeAcquire(request),
159
+ ([, queue]) => Effect.flatten(Queue.take(queue)),
160
+ executeRelease
161
+ )
162
+
163
+ const handleMessages = yield* _(
164
+ Queue.take(backing.queue),
165
+ Effect.flatMap(handleMessage),
166
+ Effect.forever,
167
+ Effect.forkDaemon
168
+ )
169
+ yield* _(Effect.addFinalizer(() => handleMessages.interruptAsFork(fiberId)))
170
+
171
+ const postMessages = yield* _(
172
+ semaphore.take(1),
173
+ Effect.zipRight(outbound.take),
174
+ Effect.flatMap(([id, request]) =>
175
+ pipe(
176
+ Effect.suspend(() => {
177
+ const result = requestMap.get(id)
178
+ if (!result) return Effect.unit
179
+ const transferables = transfers(request)
180
+ return Effect.zipRight(
181
+ backing.send([id, 0, request], transferables),
182
+ Deferred.await(result[1])
183
+ )
184
+ }),
185
+ Effect.ensuring(semaphore.release(1)),
186
+ Effect.fork
187
+ )
188
+ ),
189
+ Effect.forever,
190
+ Effect.forkDaemon
191
+ )
192
+ yield* _(Effect.addFinalizer(() => postMessages.interruptAsFork(fiberId)))
193
+
194
+ const join = Effect.race(
195
+ Fiber.joinAll([
196
+ handleMessages,
197
+ postMessages
198
+ ]),
199
+ backing.join
200
+ ) as Effect.Effect<never, WorkerError, never>
201
+
202
+ return { id, join, execute, executeEffect }
203
+ })
204
+ }
205
+ })
206
+ })
207
+
208
+ /** @internal */
209
+ export const layerManager = Layer.effect(WorkerManager, makeManager)
210
+
211
+ /** @internal */
212
+ export const makePool = <W>() =>
213
+ <I, E, O>(
214
+ options: Worker.WorkerPool.Options<I, W>
215
+ ) =>
216
+ Effect.gen(function*(_) {
217
+ const manager = yield* _(WorkerManager)
218
+ const backing = yield* _(
219
+ "timeToLive" in options ?
220
+ Pool.makeWithTTL({
221
+ acquire: manager.spawn<I, E, O>(options),
222
+ min: options.minSize,
223
+ max: options.maxSize,
224
+ timeToLive: options.timeToLive
225
+ }) :
226
+ Pool.make({
227
+ acquire: manager.spawn<I, E, O>(options),
228
+ size: options.size
229
+ })
230
+ )
231
+ const pool: Worker.WorkerPool<I, E, O> = {
232
+ backing,
233
+ execute: (message: I) =>
234
+ Stream.unwrap(
235
+ Effect.map(
236
+ Effect.scoped(backing.get()),
237
+ (worker) => worker.execute(message)
238
+ )
239
+ ),
240
+ executeEffect: (message: I) =>
241
+ Effect.flatMap(
242
+ Effect.scoped(backing.get()),
243
+ (worker) => worker.executeEffect(message)
244
+ )
245
+ }
246
+
247
+ return pool
248
+ })
249
+
250
+ /** @internal */
251
+ export const makePoolLayer = <W>(managerLayer: Layer.Layer<never, never, Worker.WorkerManager>) =>
252
+ <Tag, I, E, O>(
253
+ tag: Context.Tag<Tag, Worker.WorkerPool<I, E, O>>,
254
+ options: Worker.WorkerPool.Options<I, W>
255
+ ) =>
256
+ Layer.provide(
257
+ managerLayer,
258
+ Layer.scoped(
259
+ tag,
260
+ makePool<W>()(options)
261
+ )
262
+ )
@@ -0,0 +1,16 @@
1
+ import * as Data from "effect/Data"
2
+ import type * as WorkerError_ from "../WorkerError"
3
+
4
+ /** @internal */
5
+ export const WorkerErrorTypeId: WorkerError_.WorkerErrorTypeId = Symbol.for(
6
+ "@effect-ts/platform/Worker/WorkerError"
7
+ ) as WorkerError_.WorkerErrorTypeId
8
+
9
+ /** @internal */
10
+ export const WorkerError = (reason: WorkerError_.WorkerError["reason"], error: unknown): WorkerError_.WorkerError =>
11
+ Data.struct({
12
+ [WorkerErrorTypeId]: WorkerErrorTypeId,
13
+ _tag: "WorkerError",
14
+ reason,
15
+ error
16
+ })