@graftland/plugin-remote 0.3.1 → 0.3.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/Auth.d.ts +2 -2
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js.map +1 -1
- package/dist/{Bootstrap-Dr6sX7el.js → Bootstrap-H9gDsgsC.js} +2 -2
- package/dist/{Contract-DL2mHvaT.js → Contract-DsJtisvL.js} +2 -2
- package/dist/Contract.js +1 -1
- package/dist/{Errors-BMKmu5Y7.js → Errors-DYhsGZcZ.js} +3 -1
- package/dist/Errors.d.ts +7 -0
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js +3 -1
- package/dist/Errors.js.map +1 -1
- package/dist/{FailureGroup-BcH0XOBi.js → FailureGroup-BgT73AaR.js} +14 -4
- package/dist/{Framing-zaYdOJnT.js → Framing-G9eSaeLb.js} +1 -1
- package/dist/{Graft-CVyueNOf.js → Graft-B71CPA2Y.js} +20 -16
- package/dist/{Packages-JNL34JpS.js → Packages-AgoCGotL.js} +23 -26
- package/dist/{Peer-BT7eAGmh.js → Peer-DXeVrGBh.js} +5 -5
- package/dist/{ProcessObservation-DEGrEMfP.js → ProcessObservation-gLgGirYv.js} +1 -1
- package/dist/{ServeLifecycle-CJM0gG5B.js → ServeLifecycle-Bd1FPJ6e.js} +1 -1
- package/dist/Transport.d.ts +2 -2
- package/dist/Transport.d.ts.map +1 -1
- package/dist/Transport.js.map +1 -1
- package/dist/bin.js +48 -47
- package/dist/bin.js.map +1 -1
- package/dist/{childRuntime-An0HsIzl.js → childRuntime-Bm3iSg_N.js} +29 -26
- package/dist/{connectionEnded-DCpFCjMX.js → connectionEnded-BwcxQ7W8.js} +4 -4
- package/dist/{entry-B89sepMU.js → entry-psOpX3Bj.js} +72 -35
- package/dist/host/auth/bearer.d.ts +9 -1
- package/dist/host/auth/bearer.d.ts.map +1 -1
- package/dist/host/auth/bearer.js +1 -1
- package/dist/host/auth/jwt.d.ts +9 -1
- package/dist/host/auth/jwt.d.ts.map +1 -1
- package/dist/host/auth/jwt.js +1 -1
- package/dist/host/auth/mtls.d.ts +8 -1
- package/dist/host/auth/mtls.d.ts.map +1 -1
- package/dist/host/auth/mtls.js +2 -2
- package/dist/host/auth/none.d.ts +3 -1
- package/dist/host/auth/none.js +1 -1
- package/dist/host/command.d.ts +14 -1
- package/dist/host/command.d.ts.map +1 -1
- package/dist/host/command.js +4 -4
- package/dist/host/local.d.ts +2 -1
- package/dist/host/local.d.ts.map +1 -1
- package/dist/host/local.js +3 -3
- package/dist/host/unix.d.ts +6 -1
- package/dist/host/unix.d.ts.map +1 -1
- package/dist/host/unix.js +3 -3
- package/dist/host/websocket.d.ts +10 -1
- package/dist/host/websocket.d.ts.map +1 -1
- package/dist/host/websocket.js +3 -3
- package/dist/host/worker.d.ts +3 -1
- package/dist/host/worker.d.ts.map +1 -1
- package/dist/host/worker.js +4 -5
- package/dist/{importer-Bk6U_sn4.js → importer-Cvf88eAY.js} +5 -8
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/internal/Certificates.js +4 -4
- package/dist/internal/Certificates.js.map +1 -1
- package/dist/internal/FailureGroup.js +3 -2
- package/dist/internal/FailureGroup.js.map +1 -1
- package/dist/internal/assembly.d.ts +2 -1
- package/dist/internal/assembly.js +9 -2
- package/dist/internal/assembly.js.map +1 -1
- package/dist/internal/auth/mtls.js +1 -1
- package/dist/internal/auth/mtls.js.map +1 -1
- package/dist/internal/auth/tokenCredentials.d.ts +2 -1
- package/dist/internal/auth/tokenCredentials.d.ts.map +1 -1
- package/dist/internal/child.js +20 -17
- package/dist/internal/child.js.map +1 -1
- package/dist/internal/childRuntime.js +4 -4
- package/dist/internal/childRuntime.js.map +1 -1
- package/dist/internal/credentials.d.ts +1 -1
- package/dist/internal/directTransport.d.ts +1 -1
- package/dist/internal/entry.d.ts +415 -3
- package/dist/internal/entry.d.ts.map +1 -1
- package/dist/internal/entry.js +1 -1
- package/dist/internal/entry.js.map +1 -1
- package/dist/internal/execution.js +40 -5
- package/dist/internal/execution.js.map +1 -1
- package/dist/internal/host/runner.js +7 -6
- package/dist/internal/host/runner.js.map +1 -1
- package/dist/internal/host.js +5 -5
- package/dist/internal/host.js.map +1 -1
- package/dist/internal/port.js +5 -5
- package/dist/internal/port.js.map +1 -1
- package/dist/internal/release.js +1 -1
- package/dist/internal/release.js.map +1 -1
- package/dist/internal/runner/Connection.d.ts +1 -1
- package/dist/internal/runner/Connection.js +4 -4
- package/dist/internal/runner/Connection.js.map +1 -1
- package/dist/internal/runner/Execution.js +3 -3
- package/dist/internal/runner/Execution.js.map +1 -1
- package/dist/internal/runner/Framing.js +1 -1
- package/dist/internal/runner/Framing.js.map +1 -1
- package/dist/internal/runner/Local.js +1 -1
- package/dist/internal/runner/Local.js.map +1 -1
- package/dist/internal/runner/Lock.js +1 -1
- package/dist/internal/runner/Lock.js.map +1 -1
- package/dist/internal/runner/Packages.d.ts +1 -1
- package/dist/internal/runner/Packages.js +22 -25
- package/dist/internal/runner/Packages.js.map +1 -1
- package/dist/internal/runner/Processes.js +7 -9
- package/dist/internal/runner/Processes.js.map +1 -1
- package/dist/internal/runner/Store.js +3 -3
- package/dist/internal/runner/Store.js.map +1 -1
- package/dist/internal/runner/Supervisor.js +46 -47
- package/dist/internal/runner/Supervisor.js.map +1 -1
- package/dist/internal/runner/accept.js +3 -3
- package/dist/internal/runner/accept.js.map +1 -1
- package/dist/internal/runner/model.js +1 -1
- package/dist/internal/runner/model.js.map +1 -1
- package/dist/internal/serve.js +1 -1
- package/dist/internal/serve.js.map +1 -1
- package/dist/internal/supervisorPlugin.js +1 -1
- package/dist/internal/watchdogMain.js +5 -5
- package/dist/internal/watchdogMain.js.map +1 -1
- package/dist/internal/websocketServer.js +3 -1
- package/dist/internal/websocketServer.js.map +1 -1
- package/dist/internal/workerMain.js +3 -3
- package/dist/{port-DSVUY8Bq.js → port--3x2zJ4D.js} +8 -8
- package/dist/{release-BY4Mlluy.js → release-DfZPuIcK.js} +1 -1
- package/dist/runner/auth/bearer.d.ts +6 -1
- package/dist/runner/auth/bearer.d.ts.map +1 -1
- package/dist/runner/auth/bearer.js +2 -2
- package/dist/runner/auth/jwt.d.ts +29 -2
- package/dist/runner/auth/jwt.d.ts.map +1 -1
- package/dist/runner/auth/jwt.js +4 -4
- package/dist/runner/auth/jwt.js.map +1 -1
- package/dist/runner/auth/mtls.d.ts +6 -1
- package/dist/runner/auth/mtls.d.ts.map +1 -1
- package/dist/runner/auth/mtls.js +3 -3
- package/dist/runner/auth/none.d.ts +7 -1
- package/dist/runner/auth/none.js +1 -1
- package/dist/runner/index.d.ts +310 -1
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/index.js +5 -5
- package/dist/runner/stdio.d.ts +6 -1
- package/dist/runner/stdio.d.ts.map +1 -1
- package/dist/runner/stdio.js +3 -3
- package/dist/runner/unix.d.ts +6 -1
- package/dist/runner/unix.d.ts.map +1 -1
- package/dist/runner/unix.js +3 -3
- package/dist/runner/websocket.d.ts +24 -1
- package/dist/runner/websocket.d.ts.map +1 -1
- package/dist/runner/websocket.js +4 -4
- package/dist/{socketChannel-C_ppdSzz.js → socketChannel-CJvL2DiB.js} +2 -2
- package/dist/{supervisorPlugin-CivhM7x5.js → supervisorPlugin-t6Z6PrhD.js} +72 -76
- package/dist/{token-Cc_1CTbE.js → token-CYBNNlhS.js} +1 -1
- package/dist/{tokenCredentials-CI6mMRRd.js → tokenCredentials-CbCuk-Rt.js} +3 -3
- package/dist/{websocketServer-D2Hk7wsA.js → websocketServer-NQhODlEt.js} +5 -3
- package/dist/{workerChannel-cmLc13vm.js → workerChannel-C8hhBJzA.js} +1 -1
- package/package.json +4 -4
- package/src/Auth.ts +9 -2
- package/src/Errors.ts +8 -0
- package/src/Transport.ts +6 -2
- package/src/bin.ts +28 -30
- package/src/index.ts +5 -3
- package/src/internal/Certificates.ts +10 -13
- package/src/internal/FailureGroup.ts +128 -121
- package/src/internal/assembly.ts +19 -10
- package/src/internal/auth/mtls.ts +19 -20
- package/src/internal/child.ts +248 -239
- package/src/internal/childRuntime.ts +81 -80
- package/src/internal/entry.ts +10 -11
- package/src/internal/execution.ts +69 -12
- package/src/internal/host/runner.ts +153 -153
- package/src/internal/host.ts +116 -120
- package/src/internal/port.ts +100 -103
- package/src/internal/release.ts +3 -2
- package/src/internal/runner/Connection.ts +52 -60
- package/src/internal/runner/Execution.ts +163 -164
- package/src/internal/runner/Framing.ts +9 -10
- package/src/internal/runner/Local.ts +26 -27
- package/src/internal/runner/Lock.ts +23 -25
- package/src/internal/runner/Packages.ts +67 -70
- package/src/internal/runner/Processes.ts +89 -92
- package/src/internal/runner/Store.ts +110 -114
- package/src/internal/runner/Supervisor.ts +392 -405
- package/src/internal/runner/accept.ts +76 -84
- package/src/internal/runner/model.ts +20 -21
- package/src/internal/serve.ts +15 -13
- package/src/internal/watchdogMain.ts +16 -11
- package/src/internal/websocketServer.ts +18 -3
- package/src/runner/auth/jwt.ts +10 -6
- package/dist/cleanup-CXLa1Wd9.js +0 -13
|
@@ -291,88 +291,83 @@ const exitCause = <A, E>(exit: Exit.Exit<A, E>) =>
|
|
|
291
291
|
Exit.isFailure(exit) ? exit.cause : Cause.empty
|
|
292
292
|
|
|
293
293
|
/** A signal is a request; only the exited effect confirms that the execution has stopped. */
|
|
294
|
-
const terminate = (
|
|
294
|
+
const terminate = Effect.fnUntraced(function* (
|
|
295
295
|
execution: ExecutionState,
|
|
296
296
|
grace: number,
|
|
297
297
|
confirmation: number,
|
|
298
|
-
): Effect.
|
|
299
|
-
if (execution._tag === "Absent") return
|
|
298
|
+
): Effect.fn.Return<Termination, TerminationUnconfirmed> {
|
|
299
|
+
if (execution._tag === "Absent") return emptyTermination
|
|
300
300
|
if (execution._tag === "Exited")
|
|
301
|
-
return
|
|
301
|
+
return { ...emptyTermination, exit: execution.exit }
|
|
302
302
|
const child = execution.unit
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
detail: "The child exit could not be confirmed",
|
|
323
|
-
cause,
|
|
324
|
-
})
|
|
325
|
-
return {
|
|
326
|
-
kind: "Killed",
|
|
327
|
-
exit: forced.value.value,
|
|
303
|
+
const graceful = yield* child.interrupt.pipe(
|
|
304
|
+
Effect.andThen(child.exited),
|
|
305
|
+
Effect.timeoutOption(grace),
|
|
306
|
+
Effect.exit,
|
|
307
|
+
)
|
|
308
|
+
if (Exit.isSuccess(graceful) && Option.isSome(graceful.value))
|
|
309
|
+
return { ...emptyTermination, exit: graceful.value.value }
|
|
310
|
+
const killed = yield* Effect.exit(child.kill)
|
|
311
|
+
const forced = yield* child.exited.pipe(
|
|
312
|
+
Effect.timeoutOption(confirmation),
|
|
313
|
+
Effect.exit,
|
|
314
|
+
)
|
|
315
|
+
const cause = Cause.combine(
|
|
316
|
+
Cause.combine(exitCause(graceful), exitCause(killed)),
|
|
317
|
+
exitCause(forced),
|
|
318
|
+
)
|
|
319
|
+
if (Exit.isFailure(forced) || Option.isNone(forced.value))
|
|
320
|
+
return yield* TerminationUnconfirmed.make({
|
|
321
|
+
detail: "The child exit could not be confirmed",
|
|
328
322
|
cause,
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
|
|
323
|
+
})
|
|
324
|
+
return {
|
|
325
|
+
kind: "Killed",
|
|
326
|
+
exit: forced.value.value,
|
|
327
|
+
cause,
|
|
328
|
+
} satisfies Termination
|
|
329
|
+
})
|
|
332
330
|
|
|
333
|
-
const initialize = (options: Options = {})
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
closing,
|
|
374
|
-
}
|
|
375
|
-
})
|
|
331
|
+
const initialize = Effect.fnUntraced(function* (options: Options = {}) {
|
|
332
|
+
const store = yield* Store
|
|
333
|
+
const execution = yield* Execution
|
|
334
|
+
const random = yield* SecureRandom.SecureRandom
|
|
335
|
+
const parent = yield* Effect.scope
|
|
336
|
+
const owner = yield* Scope.fork(parent)
|
|
337
|
+
// Cleanup must continue after a health failure so every registered process is reaped.
|
|
338
|
+
const workers = yield* FiberSet.make<void, never>().pipe(Scope.provide(owner))
|
|
339
|
+
const locks = yield* RcMap.make({
|
|
340
|
+
lookup: (_key: SessionKey) => Semaphore.make(1),
|
|
341
|
+
}).pipe(Scope.provide(owner))
|
|
342
|
+
const lease = Duration.toMillis(options.lease ?? "15 seconds")
|
|
343
|
+
const grace = Duration.toMillis(options.grace ?? "5 seconds")
|
|
344
|
+
const confirmation = Duration.toMillis(
|
|
345
|
+
options.confirmationTimeout ?? "5 seconds",
|
|
346
|
+
)
|
|
347
|
+
const limits = options.limits ?? defaults
|
|
348
|
+
const records = yield* Ref.make(HashMap.empty<string, SessionRecord>())
|
|
349
|
+
const entries = yield* Ref.make(HashMap.empty<string, Entry>())
|
|
350
|
+
const health = yield* FailureGroup.make<SupervisorError>().pipe(
|
|
351
|
+
Scope.provide(owner),
|
|
352
|
+
)
|
|
353
|
+
const closing = yield* Ref.make(false)
|
|
354
|
+
return {
|
|
355
|
+
store,
|
|
356
|
+
execution,
|
|
357
|
+
random,
|
|
358
|
+
owner,
|
|
359
|
+
workers,
|
|
360
|
+
locks,
|
|
361
|
+
lease,
|
|
362
|
+
grace,
|
|
363
|
+
confirmation,
|
|
364
|
+
limits,
|
|
365
|
+
records,
|
|
366
|
+
entries,
|
|
367
|
+
health,
|
|
368
|
+
closing,
|
|
369
|
+
}
|
|
370
|
+
})
|
|
376
371
|
type Runtime = Effect.Success<ReturnType<typeof initialize>>
|
|
377
372
|
const operations = (runtime: Runtime) => {
|
|
378
373
|
const {
|
|
@@ -435,82 +430,78 @@ const operations = (runtime: Runtime) => {
|
|
|
435
430
|
),
|
|
436
431
|
),
|
|
437
432
|
)
|
|
438
|
-
const entryFor = (handle: Handle)
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
})
|
|
433
|
+
const entryFor = Effect.fnUntraced(function* (handle: Handle) {
|
|
434
|
+
yield* status(handle)
|
|
435
|
+
const all = yield* Ref.get(entries)
|
|
436
|
+
const found = HashMap.get(all, handle.token)
|
|
437
|
+
if (Option.isNone(found))
|
|
438
|
+
return yield* SessionStopped.make({
|
|
439
|
+
detail: "The session was retired during recovery",
|
|
440
|
+
})
|
|
441
|
+
return found.value
|
|
442
|
+
})
|
|
449
443
|
const commit = (
|
|
450
444
|
entry: Entry,
|
|
451
445
|
transition: (
|
|
452
446
|
state: Session,
|
|
453
447
|
) => Result.Result<Session, ExecutionError | SessionStopped>,
|
|
454
448
|
) =>
|
|
455
|
-
SynchronizedRef.updateEffect(
|
|
456
|
-
|
|
449
|
+
SynchronizedRef.updateEffect(
|
|
450
|
+
entry.state,
|
|
451
|
+
Effect.fnUntraced(function* (state: Session) {
|
|
457
452
|
const next = yield* Effect.fromResult(transition(state))
|
|
458
453
|
yield* persist(snapshot(next))
|
|
459
454
|
return next
|
|
460
455
|
}),
|
|
461
456
|
)
|
|
462
|
-
const finishStop = (
|
|
457
|
+
const finishStop = Effect.fnUntraced(function* (
|
|
463
458
|
entry: Entry,
|
|
464
459
|
state: Stopping,
|
|
465
460
|
saved: Exit.Exit<void, StateStorageError>,
|
|
466
|
-
)
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
if (Exit.isFailure(saved)) return yield* Effect.failCause(saved.cause)
|
|
488
|
-
return termination
|
|
489
|
-
})
|
|
461
|
+
) {
|
|
462
|
+
yield* FiberHandle.clear(entry.loading)
|
|
463
|
+
const result = yield* terminate(state.execution, grace, confirmation)
|
|
464
|
+
const closed = yield* Effect.exit(Release.close(entry.unitScope, Exit.void))
|
|
465
|
+
const termination: Termination = {
|
|
466
|
+
...result,
|
|
467
|
+
cause: Cause.combine(result.cause, exitCause(closed)),
|
|
468
|
+
}
|
|
469
|
+
const record = stoppedRecord(
|
|
470
|
+
state.record.previous,
|
|
471
|
+
state.record.reason,
|
|
472
|
+
termination,
|
|
473
|
+
)
|
|
474
|
+
yield* SynchronizedRef.updateEffect(entry.state, () =>
|
|
475
|
+
persist(record).pipe(
|
|
476
|
+
Effect.as(Session.Stopped({ record, reply: state.reply })),
|
|
477
|
+
),
|
|
478
|
+
)
|
|
479
|
+
if (Exit.isFailure(saved)) return yield* Effect.failCause(saved.cause)
|
|
480
|
+
return termination
|
|
481
|
+
})
|
|
490
482
|
/** Called with the session ref locked; the worker starts after its transition is published. */
|
|
491
|
-
const stopLocked = (
|
|
483
|
+
const stopLocked = Effect.fnUntraced(function* (
|
|
492
484
|
entry: Entry,
|
|
493
485
|
state: Session,
|
|
494
486
|
reason: StopReason,
|
|
495
487
|
exit: Option.Option<ExitStatus>,
|
|
496
|
-
): Effect.
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
})
|
|
488
|
+
): Effect.fn.Return<readonly [StopReply, Session]> {
|
|
489
|
+
if (state._tag === "Stopping" || state._tag === "Stopped")
|
|
490
|
+
return [state.reply, state] as const
|
|
491
|
+
const reply = yield* Deferred.make<Termination, SupervisorError>()
|
|
492
|
+
const next = beginStop(state, reason, reply, exit)
|
|
493
|
+
// Fence in memory even when the journal cannot acknowledge the transition.
|
|
494
|
+
const saved = yield* Effect.exit(persist(next.record))
|
|
495
|
+
yield* FiberSet.run(
|
|
496
|
+
workers,
|
|
497
|
+
finishStop(entry, next, saved).pipe(
|
|
498
|
+
Effect.onExit((result) => Deferred.done(reply, result)),
|
|
499
|
+
observe,
|
|
500
|
+
),
|
|
501
|
+
{ startImmediately: false },
|
|
502
|
+
)
|
|
503
|
+
return [reply, next] as const
|
|
504
|
+
})
|
|
514
505
|
const stop = (
|
|
515
506
|
entry: Entry,
|
|
516
507
|
reason: StopReason,
|
|
@@ -547,8 +538,9 @@ const operations = (runtime: Runtime) => {
|
|
|
547
538
|
{ startImmediately: false },
|
|
548
539
|
)
|
|
549
540
|
const register = (entry: Entry, unit: Unit) =>
|
|
550
|
-
SynchronizedRef.updateEffect(
|
|
551
|
-
|
|
541
|
+
SynchronizedRef.updateEffect(
|
|
542
|
+
entry.state,
|
|
543
|
+
Effect.fnUntraced(function* (state: Session) {
|
|
552
544
|
const now = yield* Clock.monotonicTimeNanos
|
|
553
545
|
const current = yield* Effect.fromResult(live(state, now))
|
|
554
546
|
const next = yield* Effect.fromResult(registerUnit(current, unit))
|
|
@@ -582,8 +574,10 @@ const operations = (runtime: Runtime) => {
|
|
|
582
574
|
),
|
|
583
575
|
),
|
|
584
576
|
Effect.tap((code) => commit(entry, (current) => loaded(current, code))),
|
|
585
|
-
Effect.onExit(
|
|
586
|
-
Effect.
|
|
577
|
+
Effect.onExit(
|
|
578
|
+
Effect.fnUntraced(function* (
|
|
579
|
+
result: Exit.Exit<CodeIdentity, SupervisorError>,
|
|
580
|
+
) {
|
|
587
581
|
if (Exit.isSuccess(result)) {
|
|
588
582
|
yield* Deferred.done(state.reply, result)
|
|
589
583
|
return
|
|
@@ -615,287 +609,280 @@ const operations = (runtime: Runtime) => {
|
|
|
615
609
|
}
|
|
616
610
|
}
|
|
617
611
|
type Operations = ReturnType<typeof operations>
|
|
618
|
-
const recover = (
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
612
|
+
const recover = Effect.fnUntraced(function* (
|
|
613
|
+
runtime: Runtime,
|
|
614
|
+
actions: Operations,
|
|
615
|
+
) {
|
|
616
|
+
const { store, execution, confirmation, records } = runtime
|
|
617
|
+
const { persist } = actions
|
|
618
|
+
// Recover before the service is published. Construction does not resume old leases.
|
|
619
|
+
const stored = yield* store.list
|
|
620
|
+
yield* Ref.set(
|
|
621
|
+
records,
|
|
622
|
+
HashMap.fromIterable(
|
|
623
|
+
Array.map(stored, (record) => [record.handle.token, record] as const),
|
|
624
|
+
),
|
|
625
|
+
)
|
|
626
|
+
for (const record of stored) {
|
|
627
|
+
if (record.phase === "Stopped") continue
|
|
628
|
+
const child = childOf(record)
|
|
629
|
+
const termination = Option.isNone(child)
|
|
630
|
+
? emptyTermination
|
|
631
|
+
: yield* execution.recover(child.value).pipe(
|
|
632
|
+
Effect.timeout(confirmation),
|
|
633
|
+
Effect.catchTags({
|
|
634
|
+
ExecutionError: (error) =>
|
|
635
|
+
Effect.fail(
|
|
636
|
+
TerminationUnconfirmed.make({
|
|
637
|
+
detail: "Orphan recovery did not confirm exit",
|
|
638
|
+
cause: Cause.fail(error),
|
|
639
|
+
}),
|
|
640
|
+
),
|
|
641
|
+
TimeoutError: (error) =>
|
|
642
|
+
Effect.fail(
|
|
643
|
+
TerminationUnconfirmed.make({
|
|
644
|
+
detail: "Orphan recovery did not confirm exit",
|
|
645
|
+
cause: Cause.fail(error),
|
|
646
|
+
}),
|
|
647
|
+
),
|
|
648
|
+
}),
|
|
649
|
+
)
|
|
650
|
+
yield* persist(
|
|
651
|
+
stoppedRecord(
|
|
652
|
+
record.phase === "Stopping" ? record.previous : record,
|
|
653
|
+
{ _tag: "Recovery" },
|
|
654
|
+
termination,
|
|
628
655
|
),
|
|
629
656
|
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
Effect.fail(
|
|
647
|
-
TerminationUnconfirmed.make({
|
|
648
|
-
detail: "Orphan recovery did not confirm exit",
|
|
649
|
-
cause: Cause.fail(error),
|
|
650
|
-
}),
|
|
651
|
-
),
|
|
652
|
-
}),
|
|
653
|
-
)
|
|
654
|
-
yield* persist(
|
|
655
|
-
stoppedRecord(
|
|
656
|
-
record.phase === "Stopping" ? record.previous : record,
|
|
657
|
-
{ _tag: "Recovery" },
|
|
658
|
-
termination,
|
|
657
|
+
}
|
|
658
|
+
})
|
|
659
|
+
const ownShutdown = Effect.fnUntraced(function* (
|
|
660
|
+
runtime: Runtime,
|
|
661
|
+
actions: Operations,
|
|
662
|
+
) {
|
|
663
|
+
const { entries, health, closing } = runtime
|
|
664
|
+
const { stop } = actions
|
|
665
|
+
yield* Effect.addFinalizer(
|
|
666
|
+
Effect.fnUntraced(function* () {
|
|
667
|
+
yield* Ref.set(closing, true)
|
|
668
|
+
const all = yield* Ref.get(entries)
|
|
669
|
+
const exits = yield* Effect.forEach(HashMap.values(all), (entry) =>
|
|
670
|
+
stop(entry, { _tag: "Shutdown" }).pipe(
|
|
671
|
+
Effect.flatMap(Deferred.await),
|
|
672
|
+
Effect.exit,
|
|
659
673
|
),
|
|
660
674
|
)
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
yield*
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
675
|
+
const initial: Cause.Cause<unknown> = yield* health.cause
|
|
676
|
+
const cause = Array.reduce(exits, initial, (cause, exit) =>
|
|
677
|
+
Cause.combine(
|
|
678
|
+
cause,
|
|
679
|
+
Exit.isFailure(exit) ? exit.cause : exit.value.cause,
|
|
680
|
+
),
|
|
681
|
+
)
|
|
682
|
+
if (cause.reasons.length > 0)
|
|
683
|
+
return yield* Effect.failCause(cleanupCause(cause))
|
|
684
|
+
}),
|
|
685
|
+
)
|
|
686
|
+
})
|
|
687
|
+
const protocol = Effect.fnUntraced(function* (
|
|
688
|
+
runtime: Runtime,
|
|
689
|
+
actions: Operations,
|
|
690
|
+
) {
|
|
691
|
+
const { random, owner, locks, lease, limits, records, entries, health } =
|
|
692
|
+
runtime
|
|
693
|
+
const {
|
|
694
|
+
persist,
|
|
695
|
+
status,
|
|
696
|
+
latest,
|
|
697
|
+
entryFor,
|
|
698
|
+
stop,
|
|
699
|
+
scheduleLease,
|
|
700
|
+
runLoad,
|
|
701
|
+
healthy,
|
|
702
|
+
} = actions
|
|
703
|
+
return Supervisor.of({
|
|
704
|
+
await: health.await,
|
|
705
|
+
status,
|
|
706
|
+
highWater: (key) =>
|
|
707
|
+
latest(key).pipe(Effect.map((value) => (value === 0 ? null : value))),
|
|
708
|
+
open: Effect.fnUntraced(function* (request: Open) {
|
|
709
|
+
yield* healthy
|
|
710
|
+
const leaseMillis = Duration.toMillis(request.lease ?? lease)
|
|
711
|
+
const negotiated = negotiate(limits, request.limits ?? defaults)
|
|
712
|
+
const lock = yield* RcMap.get(locks, keyOf(request.key))
|
|
713
|
+
return yield* Effect.gen(function* () {
|
|
714
|
+
yield* healthy
|
|
715
|
+
const allRecords = yield* Ref.get(records)
|
|
716
|
+
const same = Array.filter(
|
|
717
|
+
Array.fromIterable(HashMap.values(allRecords)),
|
|
718
|
+
(row) => Equal.equals(keyOf(row.handle.key), keyOf(request.key)),
|
|
676
719
|
)
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
cause,
|
|
681
|
-
Exit.isFailure(exit) ? exit.cause : exit.value.cause,
|
|
682
|
-
),
|
|
720
|
+
const prior = Array.findFirst(
|
|
721
|
+
same,
|
|
722
|
+
(row) => row.requestId === request.requestId,
|
|
683
723
|
)
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
724
|
+
if (Option.isSome(prior)) return prior.value
|
|
725
|
+
const generation = yield* latest(request.key)
|
|
726
|
+
if (generation !== (request.expectedGeneration ?? 0))
|
|
727
|
+
return yield* StaleSession.make({
|
|
728
|
+
detail:
|
|
729
|
+
"Open expectedGeneration does not match the generation high-water mark",
|
|
730
|
+
})
|
|
731
|
+
for (const record of same) {
|
|
732
|
+
const allEntries = yield* Ref.get(entries)
|
|
733
|
+
const entry = HashMap.get(allEntries, record.handle.token)
|
|
734
|
+
if (Option.isSome(entry))
|
|
735
|
+
yield* stop(entry.value, { _tag: "Superseded" }).pipe(
|
|
736
|
+
Effect.flatMap(Deferred.await),
|
|
737
|
+
Effect.tap((result) =>
|
|
738
|
+
result.cause.reasons.length === 0
|
|
739
|
+
? Effect.void
|
|
740
|
+
: Effect.logWarning(
|
|
741
|
+
"Superseded remote execution cleanup failed",
|
|
742
|
+
result.cause,
|
|
743
|
+
).pipe(
|
|
744
|
+
Effect.annotateLogs({
|
|
745
|
+
"remote.identity": record.handle.key.identity,
|
|
746
|
+
"remote.instance": record.handle.key.instance,
|
|
747
|
+
"remote.generation": record.handle.generation,
|
|
748
|
+
}),
|
|
749
|
+
),
|
|
750
|
+
),
|
|
751
|
+
)
|
|
752
|
+
}
|
|
753
|
+
yield* healthy
|
|
754
|
+
const token = yield* random.uuidV4()
|
|
755
|
+
const record: typeof OpenRecord.Type = {
|
|
756
|
+
version: 1,
|
|
757
|
+
phase: "Open",
|
|
758
|
+
handle: {
|
|
759
|
+
key: request.key,
|
|
760
|
+
token,
|
|
761
|
+
generation: generation + 1,
|
|
762
|
+
},
|
|
763
|
+
requestId: request.requestId,
|
|
764
|
+
leaseMillis,
|
|
765
|
+
limits: negotiated,
|
|
766
|
+
}
|
|
767
|
+
return yield* Effect.uninterruptible(
|
|
710
768
|
Effect.gen(function* () {
|
|
711
|
-
yield*
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
Effect.flatMap(Deferred.await),
|
|
741
|
-
Effect.tap((result) =>
|
|
742
|
-
result.cause.reasons.length === 0
|
|
743
|
-
? Effect.void
|
|
744
|
-
: Effect.logWarning(
|
|
745
|
-
"Superseded remote execution cleanup failed",
|
|
746
|
-
result.cause,
|
|
747
|
-
).pipe(
|
|
748
|
-
Effect.annotateLogs({
|
|
749
|
-
"remote.identity": record.handle.key.identity,
|
|
750
|
-
"remote.instance": record.handle.key.instance,
|
|
751
|
-
"remote.generation": record.handle.generation,
|
|
752
|
-
}),
|
|
753
|
-
),
|
|
754
|
-
),
|
|
755
|
-
)
|
|
756
|
-
}
|
|
757
|
-
yield* healthy
|
|
758
|
-
const token = yield* random.uuidV4()
|
|
759
|
-
const record: typeof OpenRecord.Type = {
|
|
760
|
-
version: 1,
|
|
761
|
-
phase: "Open",
|
|
762
|
-
handle: {
|
|
763
|
-
key: request.key,
|
|
769
|
+
yield* persist(record)
|
|
770
|
+
const deadline =
|
|
771
|
+
(yield* Clock.monotonicTimeNanos) + nanos(leaseMillis)
|
|
772
|
+
const scope = yield* Scope.fork(owner)
|
|
773
|
+
const entry: Entry = {
|
|
774
|
+
state: yield* SynchronizedRef.make<Session>(
|
|
775
|
+
Session.Open({ record, deadline }),
|
|
776
|
+
),
|
|
777
|
+
scope,
|
|
778
|
+
unitScope: yield* Scope.fork(scope),
|
|
779
|
+
timer: yield* FiberHandle.make<void, never>().pipe(
|
|
780
|
+
Scope.provide(scope),
|
|
781
|
+
),
|
|
782
|
+
loading: yield* FiberHandle.make<void, never>().pipe(
|
|
783
|
+
Scope.provide(scope),
|
|
784
|
+
),
|
|
785
|
+
}
|
|
786
|
+
// The store's retention policy is also the in-memory eviction policy.
|
|
787
|
+
const retained = yield* Ref.get(records)
|
|
788
|
+
const old = yield* Ref.modify(
|
|
789
|
+
entries,
|
|
790
|
+
(all) =>
|
|
791
|
+
[
|
|
792
|
+
Array.filter(
|
|
793
|
+
Array.fromIterable(HashMap.entries(all)),
|
|
794
|
+
([key]) => !HashMap.has(retained, key),
|
|
795
|
+
),
|
|
796
|
+
HashMap.set(
|
|
797
|
+
HashMap.filter(all, (_, key) => HashMap.has(retained, key)),
|
|
764
798
|
token,
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
leaseMillis,
|
|
769
|
-
limits: negotiated,
|
|
770
|
-
}
|
|
771
|
-
return yield* Effect.uninterruptible(
|
|
772
|
-
Effect.gen(function* () {
|
|
773
|
-
yield* persist(record)
|
|
774
|
-
const deadline =
|
|
775
|
-
(yield* Clock.monotonicTimeNanos) + nanos(leaseMillis)
|
|
776
|
-
const scope = yield* Scope.fork(owner)
|
|
777
|
-
const entry: Entry = {
|
|
778
|
-
state: yield* SynchronizedRef.make<Session>(
|
|
779
|
-
Session.Open({ record, deadline }),
|
|
780
|
-
),
|
|
781
|
-
scope,
|
|
782
|
-
unitScope: yield* Scope.fork(scope),
|
|
783
|
-
timer: yield* FiberHandle.make<void, never>().pipe(
|
|
784
|
-
Scope.provide(scope),
|
|
785
|
-
),
|
|
786
|
-
loading: yield* FiberHandle.make<void, never>().pipe(
|
|
787
|
-
Scope.provide(scope),
|
|
788
|
-
),
|
|
789
|
-
}
|
|
790
|
-
// The store's retention policy is also the in-memory eviction policy.
|
|
791
|
-
const retained = yield* Ref.get(records)
|
|
792
|
-
const old = yield* Ref.modify(
|
|
793
|
-
entries,
|
|
794
|
-
(all) =>
|
|
795
|
-
[
|
|
796
|
-
Array.filter(
|
|
797
|
-
Array.fromIterable(HashMap.entries(all)),
|
|
798
|
-
([key]) => !HashMap.has(retained, key),
|
|
799
|
-
),
|
|
800
|
-
HashMap.set(
|
|
801
|
-
HashMap.filter(all, (_, key) =>
|
|
802
|
-
HashMap.has(retained, key),
|
|
803
|
-
),
|
|
804
|
-
token,
|
|
805
|
-
entry,
|
|
806
|
-
),
|
|
807
|
-
] as const,
|
|
808
|
-
)
|
|
809
|
-
for (const [, retired] of old)
|
|
810
|
-
yield* Release.close(retired.scope, Exit.void)
|
|
811
|
-
yield* scheduleLease(entry, deadline)
|
|
812
|
-
return record
|
|
813
|
-
}),
|
|
814
|
-
)
|
|
815
|
-
}),
|
|
799
|
+
entry,
|
|
800
|
+
),
|
|
801
|
+
] as const,
|
|
816
802
|
)
|
|
803
|
+
for (const [, retired] of old)
|
|
804
|
+
yield* Release.close(retired.scope, Exit.void)
|
|
805
|
+
yield* scheduleLease(entry, deadline)
|
|
806
|
+
return record
|
|
807
|
+
}),
|
|
808
|
+
)
|
|
809
|
+
}).pipe(lock.withPermit)
|
|
810
|
+
}, Effect.scoped),
|
|
811
|
+
renew: Effect.fnUntraced(function* (handle: Handle) {
|
|
812
|
+
yield* healthy
|
|
813
|
+
const entry = yield* entryFor(handle)
|
|
814
|
+
// Arming the new timer interrupts the old one, so the new deadline must be stored too.
|
|
815
|
+
// Telling the child may block on its control pipe, so that step stays interruptible:
|
|
816
|
+
// if it is cut short, nothing is stored and the old timer keeps its deadline.
|
|
817
|
+
return yield* Effect.uninterruptibleMask((restore) =>
|
|
818
|
+
SynchronizedRef.modifyEffect(
|
|
819
|
+
entry.state,
|
|
820
|
+
Effect.fnUntraced(function* (state: Session) {
|
|
821
|
+
const now = yield* Clock.monotonicTimeNanos
|
|
822
|
+
const current = yield* Effect.fromResult(live(state, now))
|
|
823
|
+
const running = executionOf(current)
|
|
824
|
+
if (running._tag === "Running")
|
|
825
|
+
yield* restore(running.unit.renew(current.record.leaseMillis))
|
|
826
|
+
const deadline = now + nanos(current.record.leaseMillis)
|
|
827
|
+
yield* scheduleLease(entry, deadline)
|
|
828
|
+
return [
|
|
829
|
+
current.record.leaseMillis,
|
|
830
|
+
{ ...current, deadline },
|
|
831
|
+
] as const
|
|
817
832
|
}),
|
|
818
833
|
),
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
const
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
current._tag === "Loading"
|
|
852
|
-
? current.request
|
|
853
|
-
: current.record.load
|
|
854
|
-
if (before.specifier !== request.specifier)
|
|
855
|
-
return yield* SessionConflict.make({
|
|
856
|
-
detail:
|
|
857
|
-
"Load was already requested with a different specifier",
|
|
858
|
-
})
|
|
859
|
-
return [
|
|
860
|
-
current._tag === "Loading"
|
|
861
|
-
? Deferred.await(current.reply)
|
|
862
|
-
: Effect.succeed(current.record.code),
|
|
863
|
-
current,
|
|
864
|
-
] as const
|
|
865
|
-
}
|
|
866
|
-
const done = yield* Deferred.make<
|
|
867
|
-
CodeIdentity,
|
|
868
|
-
SupervisorError
|
|
869
|
-
>()
|
|
870
|
-
const next = beginLoad(current, request, done)
|
|
871
|
-
yield* persist(snapshot(next))
|
|
872
|
-
if (next._tag === "Loading")
|
|
873
|
-
yield* FiberHandle.run(entry.loading, runLoad(entry, next), {
|
|
874
|
-
startImmediately: false,
|
|
875
|
-
})
|
|
876
|
-
return [Deferred.await(done), next] as const
|
|
877
|
-
}),
|
|
878
|
-
).pipe(Effect.uninterruptible)
|
|
879
|
-
return yield* reply
|
|
880
|
-
}),
|
|
881
|
-
dispose: (handle) =>
|
|
882
|
-
Effect.gen(function* () {
|
|
883
|
-
const record = yield* status(handle)
|
|
884
|
-
if (record.phase === "Stopped") return record.termination
|
|
885
|
-
const entry = yield* entryFor(handle)
|
|
886
|
-
return yield* stop(entry, { _tag: "Disposed" }).pipe(
|
|
887
|
-
Effect.flatMap(Deferred.await),
|
|
888
|
-
)
|
|
834
|
+
)
|
|
835
|
+
}),
|
|
836
|
+
load: Effect.fnUntraced(function* (handle: Handle, request: Load) {
|
|
837
|
+
yield* healthy
|
|
838
|
+
const entry = yield* entryFor(handle)
|
|
839
|
+
const reply = yield* SynchronizedRef.modifyEffect(
|
|
840
|
+
entry.state,
|
|
841
|
+
Effect.fnUntraced(function* (state: Session) {
|
|
842
|
+
const now = yield* Clock.monotonicTimeNanos
|
|
843
|
+
const current = yield* Effect.fromResult(live(state, now))
|
|
844
|
+
if (current._tag !== "Open") {
|
|
845
|
+
const before =
|
|
846
|
+
current._tag === "Loading" ? current.request : current.record.load
|
|
847
|
+
if (before.specifier !== request.specifier)
|
|
848
|
+
return yield* SessionConflict.make({
|
|
849
|
+
detail: "Load was already requested with a different specifier",
|
|
850
|
+
})
|
|
851
|
+
return [
|
|
852
|
+
current._tag === "Loading"
|
|
853
|
+
? Deferred.await(current.reply)
|
|
854
|
+
: Effect.succeed(current.record.code),
|
|
855
|
+
current,
|
|
856
|
+
] as const
|
|
857
|
+
}
|
|
858
|
+
const done = yield* Deferred.make<CodeIdentity, SupervisorError>()
|
|
859
|
+
const next = beginLoad(current, request, done)
|
|
860
|
+
yield* persist(snapshot(next))
|
|
861
|
+
if (next._tag === "Loading")
|
|
862
|
+
yield* FiberHandle.run(entry.loading, runLoad(entry, next), {
|
|
863
|
+
startImmediately: false,
|
|
864
|
+
})
|
|
865
|
+
return [Deferred.await(done), next] as const
|
|
889
866
|
}),
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
867
|
+
).pipe(Effect.uninterruptible)
|
|
868
|
+
return yield* reply
|
|
869
|
+
}),
|
|
870
|
+
dispose: Effect.fnUntraced(function* (handle: Handle) {
|
|
871
|
+
const record = yield* status(handle)
|
|
872
|
+
if (record.phase === "Stopped") return record.termination
|
|
873
|
+
const entry = yield* entryFor(handle)
|
|
874
|
+
return yield* stop(entry, { _tag: "Disposed" }).pipe(
|
|
875
|
+
Effect.flatMap(Deferred.await),
|
|
876
|
+
)
|
|
877
|
+
}),
|
|
899
878
|
})
|
|
879
|
+
})
|
|
880
|
+
export const make = Effect.fnUntraced(function* (options: Options = {}) {
|
|
881
|
+
const runtime = yield* initialize(options)
|
|
882
|
+
const actions = operations(runtime)
|
|
883
|
+
yield* recover(runtime, actions)
|
|
884
|
+
yield* ownShutdown(runtime, actions)
|
|
885
|
+
return yield* protocol(runtime, actions)
|
|
886
|
+
})
|
|
900
887
|
export const layer = (options: Options = {}) =>
|
|
901
888
|
Layer.effect(Supervisor, make(options))
|