@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.
- package/dist/.tsbuildinfo.json +1 -1
- package/dist/effect/BrowserChannel.d.ts +25 -0
- package/dist/effect/BrowserChannel.d.ts.map +1 -0
- package/dist/effect/BrowserChannel.js +32 -0
- package/dist/effect/BrowserChannel.js.map +1 -0
- package/dist/effect/Effect.d.ts +3 -1
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +2 -0
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/Stream.d.ts +1 -0
- package/dist/effect/Stream.d.ts.map +1 -1
- package/dist/effect/Stream.js +1 -0
- package/dist/effect/Stream.js.map +1 -1
- package/dist/effect/SubscriptionRef.d.ts +2 -2
- package/dist/effect/SubscriptionRef.d.ts.map +1 -1
- package/dist/effect/SubscriptionRef.js +2 -3
- package/dist/effect/SubscriptionRef.js.map +1 -1
- package/dist/effect/index.d.ts +3 -6
- package/dist/effect/index.d.ts.map +1 -1
- package/dist/effect/index.js +3 -8
- package/dist/effect/index.js.map +1 -1
- package/package.json +14 -14
- package/src/effect/BrowserChannel.ts +90 -0
- package/src/effect/Effect.ts +9 -1
- package/src/effect/Stream.ts +5 -0
- package/src/effect/SubscriptionRef.ts +3 -11
- package/src/effect/index.ts +4 -8
- package/dist/effect/Schema.d.ts +0 -4
- package/dist/effect/Schema.d.ts.map +0 -1
- package/dist/effect/Schema.js +0 -15
- package/dist/effect/Schema.js.map +0 -1
- package/src/effect/browser-worker-tmp/BrowserWorker.ts +0 -26
- package/src/effect/browser-worker-tmp/BrowserWorkerRunner.ts +0 -14
- package/src/effect/browser-worker-tmp/internal/worker.ts +0 -71
- package/src/effect/browser-worker-tmp/internal/workerRunner.ts +0 -119
- package/src/effect/browser-worker-tmp/port-platform-runner.ts +0 -74
- package/src/effect/worker-tmp/Worker.ts +0 -374
- package/src/effect/worker-tmp/WorkerError.ts +0 -79
- package/src/effect/worker-tmp/WorkerRunner.ts +0 -181
- package/src/effect/worker-tmp/internal/worker.ts +0 -417
- package/src/effect/worker-tmp/internal/workerError.ts +0 -6
- 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)
|