@systemfsoftware/effect-daemon-spec 0.5.0 → 0.7.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.
package/dist/index.mjs CHANGED
@@ -1,16 +1,22 @@
1
1
  import { Array as Array$1, Cause, Clock, Context, Duration, Effect, Either, Exit, Fiber, HashMap, Layer, Match, Metric, Option, Predicate, Ref, Schedule, Schema, Scope, Stream } from "effect";
2
- import { dual } from "effect/Function";
3
- import "effect/Schema";
4
- //#region src/backoff.ts
2
+ import { left, right } from "effect/Either";
3
+ import * as Match$1 from "effect/Match";
4
+ import * as S from "effect/Schema";
5
+ //#region src/backoff.kernel.ts
5
6
  const cappedBackoff = (base, cap) => {
6
7
  const ceiling = Duration.decode(cap);
7
8
  return Schedule.exponential(base).pipe(Schedule.jittered, Schedule.modifyDelay((_, delay) => Duration.min(delay, ceiling)));
8
9
  };
9
10
  //#endregion
11
+ //#region src/brands.kernel.ts
12
+ const WorkerTypeId = Symbol.for("@systemfsoftware/effect-daemon/Worker");
13
+ const SupervisorTypeId = Symbol.for("@systemfsoftware/effect-daemon/Supervisor");
14
+ const DynamicSpecTypeId = Symbol.for("@systemfsoftware/effect-daemon/DynamicSpec");
15
+ //#endregion
10
16
  //#region src/daemon-health.schema.ts
11
17
  var DynamicLimitExceeded = class extends Schema.TaggedError()("DynamicLimitExceeded", { limit: Schema.Int.pipe(Schema.greaterThanOrEqualTo(0)) }) {};
12
18
  //#endregion
13
- //#region src/daemon-metrics.ts
19
+ //#region src/daemon-metrics.kernel.ts
14
20
  const supervisorRestartsCounter = Metric.counter("app.daemon.supervisor.restart", { description: "Daemon supervisor restart count" });
15
21
  const supervisorExhaustionsCounter = Metric.counter("app.daemon.supervisor.exhaustion", { description: "Daemon supervisor exhaustion count" });
16
22
  const supervisorChildrenGauge = Metric.gauge("app.daemon.supervisor.children", { description: "Daemon supervisor current child count (dynamic supervisors only)" });
@@ -47,61 +53,75 @@ var TickPolicyConfig = class extends Schema.Class("TickPolicyConfig")({
47
53
  startLogLevel: Schema.optional(Schema.Literal("debug", "info"))
48
54
  }) {};
49
55
  //#endregion
50
- //#region src/daemon-reporter.ts
51
- var DaemonReporter = class DaemonReporter extends Context.Tag("@systemfsoftware/effect-daemon-spec/daemon-reporter/DaemonReporter")() {
52
- static Noop = Layer.succeed(DaemonReporter, DaemonReporter.of({
53
- onRestart: () => Effect.void,
54
- onExhausted: () => Effect.void
55
- }));
56
- };
57
- //#endregion
58
- //#region src/daemon-spec.ts
59
- const WorkerTypeId = Symbol.for("@systemfsoftware/effect-daemon/Worker");
60
- const SupervisorTypeId = Symbol.for("@systemfsoftware/effect-daemon/Supervisor");
61
- const DynamicSpecTypeId = Symbol.for("@systemfsoftware/effect-daemon/DynamicSpec");
62
- const isWorker = (x) => WorkerTypeId in x;
63
- const isSupervisor = (x) => SupervisorTypeId in x;
56
+ //#region src/daemon-reporter.adapter.ts
57
+ var DaemonReporter = class extends Context.Tag("@systemfsoftware/effect-daemon-spec/daemon-reporter.adapter/DaemonReporter")() {};
58
+ const Noop = Layer.succeed(DaemonReporter, DaemonReporter.of({
59
+ onRestart: () => Effect.void,
60
+ onExhausted: () => Effect.void
61
+ }));
64
62
  //#endregion
65
- //#region src/daemon.ts
66
- const make$1 = (common, loop) => ({
67
- [WorkerTypeId]: WorkerTypeId,
68
- name: common.name,
69
- loop,
70
- child: common.child ?? {},
71
- tick: common.tick,
72
- tickHooks: common.tickHooks ?? {},
73
- lock: common.lock
74
- });
75
- const poll = (opts) => {
63
+ //#region src/daemon-poll.kernel.ts
64
+ const poll$1 = (opts) => {
76
65
  if (typeof opts.prereq === "undefined") {
77
66
  const gate = Effect.succeed(Option.some(Effect.asVoid(opts.work)));
78
- return make$1(opts, {
79
- _tag: "Poll",
80
- gate,
81
- interval: opts.interval
82
- });
67
+ return {
68
+ [WorkerTypeId]: WorkerTypeId,
69
+ name: opts.name,
70
+ loop: {
71
+ _tag: "Poll",
72
+ gate,
73
+ interval: opts.interval
74
+ },
75
+ child: opts.child ?? {},
76
+ tick: opts.tick,
77
+ tickHooks: opts.tickHooks ?? {},
78
+ lock: opts.lock
79
+ };
83
80
  }
84
81
  const { prereq, work } = opts;
85
82
  const gate = Effect.map(prereq, Option.map((data) => work(data)));
86
- return make$1(opts, {
87
- _tag: "Poll",
88
- gate,
89
- interval: opts.interval
90
- });
83
+ return {
84
+ [WorkerTypeId]: WorkerTypeId,
85
+ name: opts.name,
86
+ loop: {
87
+ _tag: "Poll",
88
+ gate,
89
+ interval: opts.interval
90
+ },
91
+ child: opts.child ?? {},
92
+ tick: opts.tick,
93
+ tickHooks: opts.tickHooks ?? {},
94
+ lock: opts.lock
95
+ };
91
96
  };
92
- const stream = (opts) => make$1(opts, {
93
- _tag: "Stream",
94
- stream: opts.stream
97
+ //#endregion
98
+ //#region src/daemon-stream.kernel.ts
99
+ const stream$1 = (opts) => ({
100
+ [WorkerTypeId]: WorkerTypeId,
101
+ name: opts.name,
102
+ loop: {
103
+ _tag: "Stream",
104
+ stream: opts.stream
105
+ },
106
+ child: opts.child ?? {},
107
+ tick: opts.tick,
108
+ tickHooks: opts.tickHooks ?? {},
109
+ lock: opts.lock
95
110
  });
96
- const subscription = (opts) => make$1(opts, {
97
- _tag: "Subscription",
98
- acquire: Effect.asVoid(opts.acquire)
111
+ //#endregion
112
+ //#region src/daemon-subscription.kernel.ts
113
+ const subscription$1 = (opts) => ({
114
+ [WorkerTypeId]: WorkerTypeId,
115
+ name: opts.name,
116
+ loop: {
117
+ _tag: "Subscription",
118
+ acquire: Effect.asVoid(opts.acquire)
119
+ },
120
+ child: opts.child ?? {},
121
+ tick: opts.tick,
122
+ tickHooks: opts.tickHooks ?? {},
123
+ lock: opts.lock
99
124
  });
100
- const Daemon = {
101
- poll,
102
- stream,
103
- subscription
104
- };
105
125
  //#endregion
106
126
  //#region src/leader-lock.schema.ts
107
127
  var LeaderLockNotAcquired = class extends Schema.TaggedError()("LeaderLockNotAcquired", { key: Schema.String }) {};
@@ -110,24 +130,17 @@ var LeaderLockInfraError = class extends Schema.TaggedError()("LeaderLockInfraEr
110
130
  cause: Schema.Unknown
111
131
  }) {};
112
132
  //#endregion
113
- //#region src/leader-lock.ts
114
- var LeaderLock = class LeaderLock extends Context.Tag("@systemfsoftware/effect-daemon-spec/leader-lock/LeaderLock")() {
115
- static Noop = Layer.succeed(LeaderLock, LeaderLock.of({ withLock: (_key, self) => Effect.map(self, Option.some) }));
116
- };
117
- const withLeaderLock = dual(2, (self, options) => Effect.gen(function* () {
118
- const out = yield* (yield* LeaderLock).withLock(options.key, self);
119
- if (Option.isSome(out)) return out.value;
120
- return yield* Match.value(options.mode).pipe(Match.when("required", () => Effect.fail(new LeaderLockNotAcquired({ key: options.key }))), Match.when("optional", () => Effect.void), Match.exhaustive);
121
- }));
122
- //#endregion
123
133
  //#region src/lock-primitive.schema.ts
124
134
  var LockPrimitiveError = class extends Schema.TaggedError()("LockPrimitiveError", {
125
135
  key: Schema.String,
126
136
  cause: Schema.Unknown
127
137
  }) {};
128
138
  //#endregion
129
- //#region src/lock-primitive.ts
130
- var LockPrimitive = class extends Context.Tag("@systemfsoftware/effect-daemon-spec/lock-primitive/LockPrimitive")() {};
139
+ //#region src/leader-lock.adapter.ts
140
+ var LeaderLock = class LeaderLock extends Context.Tag("@systemfsoftware/effect-daemon-spec/leader-lock.adapter/LeaderLock")() {
141
+ static Noop = Layer.succeed(LeaderLock, LeaderLock.of({ withLock: (_key, self) => Effect.map(self, Option.some) }));
142
+ };
143
+ var LockPrimitive = class extends Context.Tag("@systemfsoftware/effect-daemon-spec/leader-lock.adapter/LockPrimitive")() {};
131
144
  const LeaderLockFromPrimitive = Layer.effect(LeaderLock, Effect.gen(function* () {
132
145
  const primitive = yield* LockPrimitive;
133
146
  return LeaderLock.of({ withLock: (key, self) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
@@ -144,13 +157,163 @@ const LeaderLockFromPrimitive = Layer.effect(LeaderLock, Effect.gen(function* ()
144
157
  })) });
145
158
  }));
146
159
  //#endregion
147
- //#region src/internal/intensity-window.ts
160
+ //#region src/internal/allocate-worker-health.kernel.ts
161
+ const allocateWorkerHealth = (name) => Effect.gen(function* () {
162
+ const ready = yield* Effect.makeLatch(false);
163
+ const healthy = yield* Effect.makeLatch(true);
164
+ const paused = yield* Effect.makeLatch(true);
165
+ yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "ready"), 0);
166
+ yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "healthy"), 1);
167
+ yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "paused"), 1);
168
+ return {
169
+ name,
170
+ ready,
171
+ healthy,
172
+ paused
173
+ };
174
+ });
175
+ //#endregion
176
+ //#region src/internal/build-worker-loop.kernel.ts
177
+ const applySpanAttributes = (hooks) => {
178
+ const { spanAttributes } = hooks;
179
+ return (effect) => {
180
+ if (typeof spanAttributes === "undefined") return effect;
181
+ return Effect.tap(effect, () => Effect.orElse(spanAttributes, () => Effect.succeed({})).pipe(Effect.flatMap(Effect.annotateCurrentSpan)));
182
+ };
183
+ };
184
+ const applyTrackDuration = (hooks) => {
185
+ const { trackDuration } = hooks;
186
+ return (effect) => {
187
+ if (typeof trackDuration === "undefined") return effect;
188
+ return Metric.trackDuration(effect, trackDuration);
189
+ };
190
+ };
191
+ const applyTimeout = (timeout) => (effect) => Effect.timeoutFail(effect, {
192
+ duration: timeout,
193
+ onTimeout: () => new Cause.TimeoutException()
194
+ });
195
+ const applyInnerRetry = (hooks) => {
196
+ const { innerRetry } = hooks;
197
+ return (effect) => {
198
+ if (typeof innerRetry === "undefined") return effect;
199
+ return Effect.retry(effect, innerRetry);
200
+ };
201
+ };
202
+ const openReadyGauge = (gauge, name) => Metric.set(Metric.tagged(Metric.tagged(gauge, "daemon", name), "latch", "ready"), 1);
203
+ const buildPollTick = (worker, health, gate, readyGauge) => {
204
+ const spanName = worker.tick.spanName ?? "daemon.tick";
205
+ const withSpanAttrs = applySpanAttributes(worker.tickHooks);
206
+ const withDuration = applyTrackDuration(worker.tickHooks);
207
+ const withTimeout = applyTimeout(worker.tick.tickTimeout);
208
+ const withInnerRetry = applyInnerRetry(worker.tickHooks);
209
+ const runWork = (work) => work.pipe(withSpanAttrs, withDuration, Effect.withSpan(spanName, {
210
+ root: true,
211
+ attributes: { "daemon.name": worker.name }
212
+ }), Effect.withLogSpan(spanName));
213
+ return withInnerRetry(withTimeout(Effect.andThen(health.paused.await, gate).pipe(Effect.flatMap(Option.match({
214
+ onNone: () => Effect.void,
215
+ onSome: runWork
216
+ }))))).pipe(Effect.tap(() => Effect.zipRight(health.ready.open, openReadyGauge(readyGauge, worker.name))), Effect.asVoid);
217
+ };
218
+ const wrapSpan = (worker, effect, spanName) => {
219
+ const finalSpan = spanName ?? "daemon.worker";
220
+ return effect.pipe(Effect.withSpan(finalSpan, {
221
+ root: true,
222
+ attributes: { "daemon.name": worker.name }
223
+ }), Effect.withLogSpan(finalSpan));
224
+ };
225
+ const buildPollLoop = (worker, loop, health, readyGauge) => {
226
+ const tick = buildPollTick(worker, health, loop.gate, readyGauge);
227
+ return Effect.repeat(tick, Schedule.spaced(loop.interval)).pipe(Effect.asVoid);
228
+ };
229
+ const propagateExit = (exit) => Match.value(exit).pipe(Match.tag("Failure", ({ cause }) => Effect.failCause(cause)), Match.orElse(() => Effect.void));
230
+ const buildStreamLoop = (worker, loop, health, readyGauge) => {
231
+ const body = Effect.gen(function* () {
232
+ yield* health.paused.await;
233
+ const fiber = yield* Effect.forkScoped(loop.stream.pipe(Stream.tap(() => Effect.zipRight(health.ready.open, openReadyGauge(readyGauge, worker.name))), Stream.runDrain));
234
+ const ready = applyTimeout(worker.tick.tickTimeout)(health.ready.await);
235
+ yield* Effect.raceFirst(ready, fiber.await.pipe(Effect.flatMap(propagateExit)));
236
+ yield* fiber.await.pipe(Effect.flatMap(propagateExit));
237
+ });
238
+ const retried = applyInnerRetry(worker.tickHooks)(body);
239
+ return wrapSpan(worker, retried.pipe(Effect.asVoid));
240
+ };
241
+ const buildSubscriptionLoop = (worker, loop, health, readyGauge) => {
242
+ const body = Effect.gen(function* () {
243
+ yield* health.paused.await;
244
+ yield* applyTimeout(worker.tick.tickTimeout)(loop.acquire);
245
+ yield* Effect.zipRight(health.ready.open, openReadyGauge(readyGauge, worker.name));
246
+ return yield* Effect.never;
247
+ });
248
+ return wrapSpan(worker, body.pipe(Effect.asVoid));
249
+ };
250
+ const buildWorkerLoop = (worker, health, readyGauge) => Match.value(worker.loop).pipe(Match.tag("Poll", (loop) => buildPollLoop(worker, loop, health, readyGauge)), Match.tag("Stream", (loop) => buildStreamLoop(worker, loop, health, readyGauge)), Match.tag("Subscription", (loop) => buildSubscriptionLoop(worker, loop, health, readyGauge)), Match.exhaustive);
251
+ //#endregion
252
+ //#region src/internal/with-leader-lock.executor.ts
253
+ var WithLeaderLockExecutorDeps = class extends Context.Tag("WithLeaderLockExecutorDeps")() {};
254
+ function withLeaderLock(self, options) {
255
+ const acquire = Effect.gen(function* () {
256
+ const out = yield* (yield* WithLeaderLockExecutorDeps).withLock(options.key, self);
257
+ if (Option.isSome(out)) return out.value;
258
+ return yield* Match.value(options.mode).pipe(Match.when("required", () => Effect.fail(new LeaderLockNotAcquired({ key: options.key }))), Match.when("optional", () => Effect.void), Match.exhaustive);
259
+ });
260
+ const retryOnce = (current) => Effect.retry(acquire, {
261
+ schedule: current,
262
+ while: Predicate.isTagged("LeaderLockNotAcquired")
263
+ }).pipe(Effect.catchTag("LeaderLockNotAcquired", () => retryOnce(current)));
264
+ const backoff = options.acquireRetryBackoff;
265
+ if (options.mode === "required" && backoff !== null && typeof backoff === "object") return retryOnce(backoff);
266
+ return acquire;
267
+ }
268
+ //#endregion
269
+ //#region src/leader-lock.kernel.ts
270
+ const isModeNone = (lock) => lock.mode === "none";
271
+ Context.Tag("DaemonWorkerExecutorDeps")();
272
+ const worker = (w) => Effect.gen(function* () {
273
+ const health = yield* allocateWorkerHealth(w.name);
274
+ const loop = buildWorkerLoop(w, health, healthStateGauge).pipe(Effect.orDie);
275
+ const lockNone = isModeNone(w.lock);
276
+ const required = !lockNone && w.lock.mode === "required";
277
+ let locked;
278
+ if (lockNone) locked = loop;
279
+ else if (required) locked = withLeaderLock(loop, {
280
+ key: w.lock.key,
281
+ mode: "required",
282
+ acquireRetryBackoff: w.lock.acquireRetryBackoff
283
+ });
284
+ else locked = withLeaderLock(loop, {
285
+ key: w.lock.key,
286
+ mode: "optional"
287
+ });
288
+ yield* Effect.forkScoped(locked.pipe(Effect.orDie));
289
+ return health;
290
+ });
291
+ //#endregion
292
+ //#region src/internal/allocate-supervisor-health.kernel.ts
293
+ const allocateSupervisorHealth = (name, children) => Effect.gen(function* () {
294
+ const ready = yield* Effect.makeLatch(false);
295
+ const healthy = yield* Effect.makeLatch(true);
296
+ const paused = yield* Effect.makeLatch(true);
297
+ yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "ready"), 0);
298
+ yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "healthy"), 1);
299
+ yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "paused"), 1);
300
+ return {
301
+ name,
302
+ ready,
303
+ healthy,
304
+ paused,
305
+ children
306
+ };
307
+ });
308
+ //#endregion
309
+ //#region src/internal/intensity-window.kernel.ts
148
310
  const isWithinWindow = (now, windowMillis) => (t) => now - t <= windowMillis;
149
- const pruneTimestamps = (ts, now, windowMillis) => ts.filter(isWithinWindow(now, windowMillis));
311
+ const keepWithin = (now, windowMillis) => (ts) => ts.filter(isWithinWindow(now, windowMillis));
312
+ const pruneTimestamps = (ts, now, windowMillis) => keepWithin(now, windowMillis)(ts);
150
313
  const recordTimestamp = (ts, now, windowMillis) => [now, ...pruneTimestamps(ts, now, windowMillis)];
151
314
  const exceedsRestarts = (count, restarts) => count > restarts;
152
315
  //#endregion
153
- //#region src/internal/intensity.ts
316
+ //#region src/internal/intensity.kernel.ts
154
317
  const neverExceeds = {
155
318
  record: Effect.void,
156
319
  isExceeded: Effect.succeed(false),
@@ -180,18 +343,10 @@ const boundedTracker = (restarts, window) => Effect.gen(function* () {
180
343
  });
181
344
  const make = (intensity) => Match.value(intensity).pipe(Match.tag("Unbounded", () => Effect.succeed(neverExceeds)), Match.tag("Bounded", ({ restarts, window }) => boundedTracker(restarts, window)), Match.exhaustive);
182
345
  //#endregion
346
+ //#region src/internal/race-for-exit.kernel.ts
347
+ const raceForExit = (fibers) => Effect.raceAll(fibers.map((f, idx) => f.await.pipe(Effect.map((exit) => [idx, exit]))));
348
+ //#endregion
183
349
  //#region src/internal/restart-decision.schema.ts
184
- const RestartDecisionTypeId = Symbol.for("@systemfsoftware/effect-daemon/RestartDecision");
185
- var Continue = class extends Schema.TaggedClass()("Continue", {}) {
186
- [RestartDecisionTypeId] = RestartDecisionTypeId;
187
- };
188
- var Restart = class extends Schema.TaggedClass()("Restart", { indices: Schema.NonEmptyArray(Schema.Int) }) {
189
- [RestartDecisionTypeId] = RestartDecisionTypeId;
190
- };
191
- var Exhausted = class extends Schema.TaggedClass()("Exhausted", {}) {
192
- [RestartDecisionTypeId] = RestartDecisionTypeId;
193
- };
194
- Schema.Union(Continue, Restart, Exhausted);
195
350
  const RestartStrategy = Schema.Literal("one_for_one", "one_for_all", "rest_for_one");
196
351
  Schema.Struct({
197
352
  strategy: RestartStrategy,
@@ -213,30 +368,24 @@ Schema.Struct({
213
368
  intensityExceeded: fc.boolean()
214
369
  }))) }));
215
370
  //#endregion
216
- //#region src/internal/restart-decision.strategy.ts
217
- const restartIndicesFor = (strategy, failedIndex, total) => {
218
- if (strategy === "one_for_one") return [failedIndex];
219
- if (strategy === "one_for_all") return [0, ...Array.from({ length: Math.max(0, total - 1) }, (_, i) => i + 1)];
220
- return [failedIndex, ...Array.from({ length: Math.max(0, total - failedIndex - 1) }, (_, i) => failedIndex + 1 + i)];
371
+ //#region src/internal/restart-decision.workflow.ts
372
+ const RestartDecisionTypeId = Symbol.for("@systemfsoftware/effect-daemon/RestartDecision");
373
+ var RestartDecisionContinue = class extends S.TaggedClass()("Continue", {}) {
374
+ [RestartDecisionTypeId] = RestartDecisionTypeId;
221
375
  };
222
- const decideRestart = (input) => {
223
- if (input.exitSuccess) return new Continue();
224
- if (input.intensityExceeded) return new Exhausted();
225
- return new Restart({ indices: restartIndicesFor(input.strategy, input.failedIndex, input.totalChildren) });
376
+ var RestartDecisionRestart = class extends S.TaggedClass()("Restart", { indices: S.NonEmptyArray(S.Int) }) {
377
+ [RestartDecisionTypeId] = RestartDecisionTypeId;
226
378
  };
379
+ var RestartDecisionExhausted = class extends S.TaggedError()("Exhausted", {}) {
380
+ [RestartDecisionTypeId] = RestartDecisionTypeId;
381
+ };
382
+ const restartIndicesFor = (strategy, failedIndex, total) => Match$1.value(strategy).pipe(Match$1.when("one_for_one", () => [failedIndex]), Match$1.when("one_for_all", () => [0, ...Array.from({ length: Math.max(0, total - 1) }, (_, i) => i + 1)]), Match$1.when("rest_for_one", () => [failedIndex, ...Array.from({ length: Math.max(0, total - failedIndex - 1) }, (_, i) => failedIndex + 1 + i)]), Match$1.exhaustive);
383
+ const decideRestart = (input) => Match$1.value(input).pipe(Match$1.when({ exitSuccess: true }, () => right(new RestartDecisionContinue())), Match$1.when({
384
+ exitSuccess: false,
385
+ intensityExceeded: true
386
+ }, () => left(new RestartDecisionExhausted())), Match$1.orElse(() => right(new RestartDecisionRestart({ indices: restartIndicesFor(input.strategy, input.failedIndex, input.totalChildren) }))));
227
387
  //#endregion
228
- //#region src/internal/supervise-index.ts
229
- const failedIndexOf = (startIdx, failedOffset) => startIdx + failedOffset;
230
- //#endregion
231
- //#region src/internal/supervision-context.strategy.ts
232
- const openAllReady = (ctx) => Effect.gen(function* () {
233
- yield* Effect.yieldNow();
234
- yield* Effect.forEach(ctx.booted, (b) => b.health.ready.await, { concurrency: "unbounded" });
235
- yield* Effect.zipRight(ctx.health.ready.open, Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", ctx.name), "latch", "ready"), 1));
236
- });
237
- const raceForExit = (fibers) => Effect.raceAll(fibers.map((f, idx) => f.await.pipe(Effect.map((exit) => [idx, exit]))));
238
- //#endregion
239
- //#region src/internal/supervise-tree.strategy.ts
388
+ //#region src/internal/supervision-epoch.schema.ts
240
389
  const EpochStepTypeId = Symbol.for("@systemfsoftware/effect-daemon/EpochStep");
241
390
  var StopEpoch = class extends Schema.TaggedClass()("StopEpoch", {}) {
242
391
  [EpochStepTypeId] = EpochStepTypeId;
@@ -256,6 +405,9 @@ var ContinueSupervision = class extends Schema.TaggedClass()("ContinueSupervisio
256
405
  [SupervisionEpochResultTypeId] = SupervisionEpochResultTypeId;
257
406
  };
258
407
  Schema.Union(StopSupervision, ContinueSupervision);
408
+ //#endregion
409
+ //#region src/internal/supervisor-body.executor.ts
410
+ var SupervisorBodyExecutorDeps = class extends Context.Tag("SupervisorBodyExecutorDeps")() {};
259
411
  const handleExhausted = (ctx, cause) => Effect.gen(function* () {
260
412
  yield* Effect.zipRight(ctx.health.healthy.close, Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", ctx.name), "latch", "healthy"), 0));
261
413
  yield* ctx.reportExhausted(cause);
@@ -272,7 +424,7 @@ const runSupervisionEpochWithBackoff = (attempt, ctx) => Effect.gen(function* ()
272
424
  const loop = () => Effect.gen(function* () {
273
425
  const step = yield* attempt.pipe(Effect.scoped);
274
426
  return yield* Match.value(step).pipe(Match.tag("StopEpoch", () => Effect.succeed(new StopSupervision())), Match.tag("CooldownEpoch", () => Effect.gen(function* () {
275
- yield* Effect.sleep(Duration.decode(ctx.policy.cooldown));
427
+ yield* Effect.sleep(ctx.policy.cooldown);
276
428
  yield* reopenHealthyAfterCooldown(ctx);
277
429
  return new ContinueSupervision();
278
430
  })), Match.tag("RestartEpoch", () => Effect.gen(function* () {
@@ -283,13 +435,18 @@ const runSupervisionEpochWithBackoff = (attempt, ctx) => Effect.gen(function* ()
283
435
  });
284
436
  return yield* loop();
285
437
  });
438
+ const openAllReady = (ctx) => Effect.gen(function* () {
439
+ yield* Effect.yieldNow();
440
+ yield* Effect.forEach(ctx.booted, (b) => b.health.ready.await, { concurrency: "unbounded" });
441
+ yield* Effect.zipRight(ctx.health.ready.open, Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", ctx.name), "latch", "ready"), 1));
442
+ });
286
443
  const superviseChild = (ctx, child, idx) => Effect.gen(function* () {
287
444
  const childIntensityOpt = yield* Option.match(Option.fromNullable(child.childPolicy.intensity), {
288
445
  onNone: () => Effect.succeed(Option.none()),
289
446
  onSome: (cfg) => Effect.map(make(new BoundedIntensity(cfg)), Option.some)
290
447
  });
291
448
  const loop = () => Effect.gen(function* () {
292
- const supIntensity = yield* make(ctx.policy.intensity);
449
+ const supIntensity = yield* ctx.intensityEff;
293
450
  const attempt = Effect.gen(function* () {
294
451
  yield* ctx.health.paused.await;
295
452
  const fiber = yield* Effect.forkScoped(child.run);
@@ -311,7 +468,10 @@ const superviseChild = (ctx, child, idx) => Effect.gen(function* () {
311
468
  failedIndex: idx,
312
469
  totalChildren: ctx.booted.length
313
470
  });
314
- return yield* Match.value(decision).pipe(Match.tag("Continue", () => Effect.succeed(new StopEpoch())), Match.tag("Exhausted", () => handleExhausted(ctx, exit.cause)), Match.tag("Restart", () => handleRestart(ctx, exit.cause, Effect.void)), Match.exhaustive);
471
+ return yield* Either.match(decision, {
472
+ onLeft: () => handleExhausted(ctx, exit.cause),
473
+ onRight: (right) => Match.value(right).pipe(Match.tag("Continue", () => Effect.succeed(new StopEpoch())), Match.tag("Restart", () => handleRestart(ctx, exit.cause, Effect.void)), Match.exhaustive)
474
+ });
315
475
  }
316
476
  return new StopEpoch();
317
477
  });
@@ -328,7 +488,7 @@ const runIndependent = (ctx) => Effect.gen(function* () {
328
488
  });
329
489
  const runGroup = (strategy, ctx) => Effect.gen(function* () {
330
490
  const loop = () => Effect.gen(function* () {
331
- const intensity = yield* make(ctx.policy.intensity);
491
+ const intensity = yield* ctx.intensityEff;
332
492
  const childIntensityTrackers = yield* Effect.forEach(ctx.booted, (b) => Option.match(Option.fromNullable(b.childPolicy.intensity), {
333
493
  onNone: () => Effect.succeed(Option.none()),
334
494
  onSome: (cfg) => Effect.map(make(new BoundedIntensity(cfg)), Option.some)
@@ -343,7 +503,7 @@ const runGroup = (strategy, ctx) => Effect.gen(function* () {
343
503
  yield* Effect.forkScoped(openAllReady(ctx));
344
504
  const [failedOffset, firstExit] = yield* raceForExit(fibers);
345
505
  if (!Exit.isSuccess(firstExit)) {
346
- const failedIdx = failedIndexOf(startIdx, failedOffset);
506
+ const failedIdx = startIdx + failedOffset;
347
507
  const failedBootedOpt = Option.fromNullable(ctx.booted[failedIdx]);
348
508
  if (Option.isNone(failedBootedOpt)) return new StopEpoch();
349
509
  if (failedBootedOpt.value.childPolicy.restart === "temporary") return new StopEpoch();
@@ -360,10 +520,13 @@ const runGroup = (strategy, ctx) => Effect.gen(function* () {
360
520
  strategy,
361
521
  exitSuccess: false,
362
522
  intensityExceeded: yield* intensity.isExceeded,
363
- failedIndex: failedIdx,
364
- totalChildren: ctx.booted.length
523
+ totalChildren: ctx.booted.length,
524
+ failedIndex: failedIdx
525
+ });
526
+ return yield* Either.match(decision, {
527
+ onLeft: () => handleExhausted(ctx, firstExit.cause),
528
+ onRight: (right) => Match.value(right).pipe(Match.tag("Continue", () => Effect.succeed(new StopEpoch())), Match.tag("Restart", (restartDecision) => handleRestart(ctx, firstExit.cause, Ref.set(cursor, restartDecision.indices[0]))), Match.exhaustive)
365
529
  });
366
- return yield* Match.value(decision).pipe(Match.tag("Continue", () => Effect.succeed(new StopEpoch())), Match.tag("Exhausted", () => handleExhausted(ctx, firstExit.cause)), Match.tag("Restart", (restartDecision) => handleRestart(ctx, firstExit.cause, Ref.set(cursor, restartDecision.indices[0]))), Match.exhaustive);
367
530
  }
368
531
  return new StopEpoch();
369
532
  });
@@ -373,13 +536,12 @@ const runGroup = (strategy, ctx) => Effect.gen(function* () {
373
536
  return yield* loop();
374
537
  });
375
538
  const superviseTree = (strategy, ctx) => Match.value(strategy).pipe(Match.when("one_for_one", () => runIndependent(ctx)), Match.when("one_for_all", () => runGroup("one_for_all", ctx)), Match.when("rest_for_one", () => runGroup("rest_for_one", ctx)), Match.exhaustive);
376
- //#endregion
377
- //#region src/internal/supervisor-runtime.ts
378
539
  const buildSupervisorBody = (sup, health, booted) => Effect.gen(function* () {
379
540
  const policy = yield* sup.supervision;
380
- const intensityEff = make(policy.intensity);
541
+ const tracker = make(policy.intensity).pipe(Effect.runSync);
542
+ const intensityEff = Effect.succeed(tracker);
381
543
  const reportRestart = (cause) => Effect.gen(function* () {
382
- const reporter = yield* DaemonReporter;
544
+ const reporter = yield* SupervisorBodyExecutorDeps;
383
545
  yield* Metric.increment(Metric.tagged(supervisorRestartsCounter, "supervisor", sup.name));
384
546
  yield* reporter.onRestart(sup.name, cause);
385
547
  yield* Option.match(Option.fromNullable(sup.reporter.onRestart), {
@@ -388,7 +550,7 @@ const buildSupervisorBody = (sup, health, booted) => Effect.gen(function* () {
388
550
  });
389
551
  });
390
552
  const reportExhausted = (cause) => Effect.gen(function* () {
391
- const reporter = yield* DaemonReporter;
553
+ const reporter = yield* SupervisorBodyExecutorDeps;
392
554
  yield* Metric.increment(Metric.tagged(supervisorExhaustionsCounter, "supervisor", sup.name));
393
555
  yield* reporter.onExhausted(sup.name, cause);
394
556
  yield* Option.match(Option.fromNullable(sup.reporter.onExhausted), {
@@ -407,143 +569,55 @@ const buildSupervisorBody = (sup, health, booted) => Effect.gen(function* () {
407
569
  });
408
570
  yield* Effect.andThen(health.paused.await, runStrategy);
409
571
  });
410
- //#endregion
411
- //#region src/internal/worker-loop.ts
412
- const applySpanAttributes = (hooks) => {
413
- const { spanAttributes } = hooks;
414
- return (effect) => {
415
- if (typeof spanAttributes === "undefined") return effect;
416
- return Effect.tap(effect, () => Effect.orElse(spanAttributes, () => Effect.succeed({})).pipe(Effect.flatMap(Effect.annotateCurrentSpan)));
417
- };
418
- };
419
- const applyTrackDuration = (hooks) => {
420
- const { trackDuration } = hooks;
421
- return (effect) => {
422
- if (typeof trackDuration === "undefined") return effect;
423
- return Metric.trackDuration(effect, trackDuration);
424
- };
425
- };
426
- const applyTimeout = (config) => {
427
- return (effect) => Effect.timeoutFail(effect, {
428
- duration: config.tickTimeout,
429
- onTimeout: () => new Cause.TimeoutException()
430
- });
431
- };
432
- const applyInnerRetry = (hooks) => {
433
- const { innerRetry } = hooks;
434
- return (effect) => {
435
- if (typeof innerRetry === "undefined") return effect;
436
- return Effect.retry(effect, innerRetry);
437
- };
438
- };
439
- const buildPollTick = (worker, health, gate) => {
440
- const { tick, tickHooks } = worker;
441
- const spanName = tick.spanName ?? "daemon.tick";
442
- const withSpanAttrs = applySpanAttributes(tickHooks);
443
- const withDuration = applyTrackDuration(tickHooks);
444
- const withTimeout = applyTimeout(tick);
445
- const withInnerRetry = applyInnerRetry(tickHooks);
446
- const runWork = (work) => work.pipe(withSpanAttrs, withDuration).pipe(Effect.withSpan(spanName, {
447
- root: true,
448
- attributes: { "daemon.name": worker.name }
449
- }), Effect.withLogSpan(spanName));
450
- return withInnerRetry(withTimeout(Effect.andThen(health.paused.await, gate).pipe(Effect.flatMap(Option.match({
451
- onNone: () => Effect.void,
452
- onSome: runWork
453
- }))))).pipe(Effect.tap(() => Effect.zipRight(health.ready.open, Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", health.name), "latch", "ready"), 1))), Effect.asVoid);
454
- };
455
- const wrapSpan = (worker, effect) => {
456
- const spanName = worker.tick.spanName ?? "daemon.worker";
457
- return effect.pipe(Effect.withSpan(spanName, {
458
- root: true,
459
- attributes: { "daemon.name": worker.name }
460
- }), Effect.withLogSpan(spanName));
461
- };
462
- const buildPollLoop = (worker, loop, health) => {
463
- const tick = buildPollTick(worker, health, loop.gate);
464
- return Effect.repeat(tick, Schedule.spaced(loop.interval)).pipe(Effect.asVoid);
465
- };
466
- const buildStreamLoop = (worker, loop, health) => {
467
- const body = Effect.gen(function* () {
468
- yield* health.paused.await;
469
- const fiber = yield* Effect.forkScoped(loop.stream.pipe(Stream.tap(() => Effect.zipRight(health.ready.open, Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", health.name), "latch", "ready"), 1))), Stream.runDrain));
470
- const ready = applyTimeout(worker.tick)(health.ready.await);
471
- yield* Effect.raceFirst(ready, Fiber.join(fiber));
472
- yield* Fiber.join(fiber);
473
- });
474
- const retried = applyInnerRetry(worker.tickHooks)(body);
475
- return wrapSpan(worker, retried.pipe(Effect.asVoid));
476
- };
477
- const buildSubscriptionLoop = (worker, loop, health) => {
478
- const body = Effect.gen(function* () {
479
- yield* health.paused.await;
480
- yield* applyTimeout(worker.tick)(loop.acquire);
481
- yield* Effect.zipRight(health.ready.open, Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", health.name), "latch", "ready"), 1));
482
- return yield* Effect.never;
483
- });
484
- return wrapSpan(worker, body.pipe(Effect.asVoid));
485
- };
486
- const buildWorkerLoop = (worker, health) => Match.value(worker.loop).pipe(Match.tag("Poll", (loop) => buildPollLoop(worker, loop, health)), Match.tag("Stream", (loop) => buildStreamLoop(worker, loop, health)), Match.tag("Subscription", (loop) => buildSubscriptionLoop(worker, loop, health)), Match.exhaustive);
487
- //#endregion
488
- //#region src/internal/boot.ts
489
- const allocateWorkerHealth = (name) => Effect.gen(function* () {
490
- const ready = yield* Effect.makeLatch(false);
491
- const healthy = yield* Effect.makeLatch(true);
492
- const paused = yield* Effect.makeLatch(true);
493
- yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "ready"), 0);
494
- yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "healthy"), 1);
495
- yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "paused"), 1);
496
- return {
497
- name,
498
- ready,
499
- healthy,
500
- paused
501
- };
502
- });
503
- const allocateSupervisorHealth = (name, children) => Effect.gen(function* () {
504
- const ready = yield* Effect.makeLatch(false);
505
- const healthy = yield* Effect.makeLatch(true);
506
- const paused = yield* Effect.makeLatch(true);
507
- yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "ready"), 0);
508
- yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "healthy"), 1);
509
- yield* Metric.set(Metric.tagged(Metric.tagged(healthStateGauge, "daemon", name), "latch", "paused"), 1);
510
- return {
511
- name,
512
- ready,
513
- healthy,
514
- paused,
515
- children
516
- };
517
- });
518
- const bootChild = (child) => {
519
- if (isWorker(child)) return allocateWorkerHealth(child.name).pipe(Effect.map((health) => ({
520
- name: child.name,
521
- health,
522
- run: buildWorkerLoop(child, health).pipe(Effect.orDie),
523
- childPolicy: child.child
524
- })));
525
- return Effect.gen(function* () {
526
- const bootedChildren = yield* Effect.forEach(child.children, bootChild);
527
- const health = yield* allocateSupervisorHealth(child.name, bootedChildren.map((b) => b.health));
528
- const run = buildSupervisorBody(child, health, bootedChildren).pipe(Effect.orDie);
572
+ const isWorker = (x) => WorkerTypeId in x;
573
+ const bootChild = (child) => Effect.gen(function* () {
574
+ if (isWorker(child)) {
575
+ const health = yield* allocateWorkerHealth(child.name);
576
+ const loop = buildWorkerLoop(child, health, healthStateGauge).pipe(Effect.orDie);
529
577
  return {
530
578
  name: child.name,
531
579
  health,
532
- run,
533
- childPolicy: {}
580
+ run: loop,
581
+ childPolicy: child.child
534
582
  };
583
+ }
584
+ const bootedChildren = yield* Effect.forEach(child.children, bootChild);
585
+ const health = yield* allocateSupervisorHealth(child.name, bootedChildren.map((b) => b.health));
586
+ const body = buildSupervisorBody(child, health, bootedChildren).pipe(Effect.orDie);
587
+ return {
588
+ name: child.name,
589
+ health,
590
+ run: body,
591
+ childPolicy: {}
592
+ };
593
+ });
594
+ const supervisor = (s) => Effect.gen(function* () {
595
+ const booted = yield* Effect.forEach(s.children, bootChild);
596
+ const health = yield* allocateSupervisorHealth(s.name, booted.map((b) => b.health));
597
+ const body = buildSupervisorBody(s, health, booted).pipe(Effect.orDie);
598
+ let locked;
599
+ if (isModeNone(s.lock)) locked = body;
600
+ else if (s.lock.mode === "required") locked = withLeaderLock(body, {
601
+ key: s.lock.key,
602
+ mode: "required",
603
+ acquireRetryBackoff: s.lock.acquireRetryBackoff
535
604
  });
536
- };
537
- //#endregion
538
- //#region src/internal/dynamic.ts
605
+ else locked = withLeaderLock(body, {
606
+ key: s.lock.key,
607
+ mode: "optional"
608
+ });
609
+ yield* Effect.forkScoped(locked.pipe(Effect.orDie));
610
+ return health;
611
+ });
612
+ Context.Tag("BuildDynamicExecutorDeps")();
539
613
  const buildDynamic = (spec, health) => Effect.gen(function* () {
540
614
  const state = yield* Ref.make({
541
615
  nextId: 0,
542
616
  children: HashMap.empty()
543
617
  });
544
618
  const startChildImpl = (args) => Effect.gen(function* () {
545
- const worker = spec.child(args);
546
- const loop = buildWorkerLoop(worker, yield* allocateWorkerHealth(worker.name)).pipe(Effect.orDie);
619
+ const childWorker = spec.child(args);
620
+ const loop = buildWorkerLoop(childWorker, yield* allocateWorkerHealth(childWorker.name), healthStateGauge).pipe(Effect.orDie);
547
621
  const removed = yield* Effect.makeLatch(false);
548
622
  const reservedId = yield* Ref.modify(state, (current) => {
549
623
  if (HashMap.size(current.children) >= spec.maxChildren) return [Option.none(), current];
@@ -620,69 +694,26 @@ const buildDynamic = (spec, health) => Effect.gen(function* () {
620
694
  count: countImpl
621
695
  };
622
696
  });
623
- //#endregion
624
- //#region src/internal/lock-gate.ts
625
- const decideLockGate = (lock) => {
626
- if (lock.mode === "none") return Option.none();
627
- return Option.some({
628
- key: lock.key,
629
- mode: lock.mode
630
- });
631
- };
632
- //#endregion
633
- //#region src/run.ts
634
- const applyLock = (lock, effect) => {
635
- const gate = decideLockGate(lock);
636
- if (Option.isNone(gate)) return effect;
637
- const locked = withLeaderLock(effect, gate.value);
638
- if (lock.mode !== "required") return locked;
639
- const retryWithRestart = (eff) => Effect.retry(eff, {
640
- schedule: lock.acquireRetryBackoff,
641
- while: Predicate.isTagged("LeaderLockNotAcquired")
642
- }).pipe(Effect.catchTag("LeaderLockNotAcquired", () => retryWithRestart(eff)));
643
- return retryWithRestart(locked);
644
- };
645
- const isModeNone = (lock) => lock.mode === "none";
646
- function worker(w) {
647
- return Effect.gen(function* () {
648
- const health = yield* allocateWorkerHealth(w.name);
649
- const loop = buildWorkerLoop(w, health).pipe(Effect.orDie);
650
- if (isModeNone(w.lock)) yield* Effect.forkScoped(loop);
651
- else {
652
- const locked = applyLock(w.lock, loop);
653
- yield* Effect.forkScoped(locked.pipe(Effect.orDie));
654
- }
655
- return health;
656
- });
657
- }
658
- function supervisor(s) {
659
- return Effect.gen(function* () {
660
- const booted = yield* Effect.forEach(s.children, bootChild);
661
- const health = yield* allocateSupervisorHealth(s.name, booted.map((b) => b.health));
662
- const body = buildSupervisorBody(s, health, booted).pipe(Effect.orDie);
663
- if (isModeNone(s.lock)) yield* Effect.forkScoped(body);
664
- else {
665
- const locked = applyLock(s.lock, body);
666
- yield* Effect.forkScoped(locked.pipe(Effect.orDie));
667
- }
668
- return health;
669
- });
670
- }
671
- const dynamic$1 = (spec) => Effect.gen(function* () {
672
- return yield* buildDynamic(spec, yield* allocateSupervisorHealth(spec.name, []));
697
+ const dynamic$2 = (spec) => Effect.gen(function* () {
698
+ const health = yield* allocateSupervisorHealth(spec.name, []);
699
+ return yield* buildDynamic(spec, health);
673
700
  });
674
- const run = {
675
- worker,
676
- supervisor,
677
- dynamic: dynamic$1
678
- };
679
701
  //#endregion
680
- //#region src/supervision-preset.ts
702
+ //#region src/internal/supervision-leader.state.ts
681
703
  var LeaderConfig = class extends Context.Reference()("@systemfsoftware/effect-daemon-spec/LeaderConfig", { defaultValue: () => ({
682
704
  backoffBase: Duration.seconds(1),
683
705
  intensity: new UnboundedIntensity(),
684
706
  cooldown: Duration.zero
685
707
  }) }) {};
708
+ //#endregion
709
+ //#region src/internal/supervision-task.state.ts
710
+ var TaskConfig = class extends Context.Reference()("@systemfsoftware/effect-daemon-spec/TaskConfig", { defaultValue: () => ({
711
+ backoffBase: Duration.seconds(1),
712
+ intensity: new UnboundedIntensity(),
713
+ cooldown: Duration.zero
714
+ }) }) {};
715
+ //#endregion
716
+ //#region src/internal/supervision-worker.state.ts
686
717
  var WorkerConfig = class extends Context.Reference()("@systemfsoftware/effect-daemon-spec/WorkerConfig", { defaultValue: () => ({
687
718
  backoffBase: Duration.seconds(10),
688
719
  intensity: new BoundedIntensity({
@@ -691,57 +722,108 @@ var WorkerConfig = class extends Context.Reference()("@systemfsoftware/effect-da
691
722
  }),
692
723
  cooldown: Duration.seconds(30)
693
724
  }) }) {};
694
- var TaskConfig = class extends Context.Reference()("@systemfsoftware/effect-daemon-spec/TaskConfig", { defaultValue: () => ({
695
- backoffBase: Duration.seconds(1),
696
- intensity: new UnboundedIntensity(),
697
- cooldown: Duration.zero
698
- }) }) {};
699
- const Supervision = {
700
- leader: (cap) => Effect.gen(function* () {
701
- const config = yield* LeaderConfig;
702
- return {
703
- intensity: config.intensity,
704
- backoff: cappedBackoff(config.backoffBase, cap),
705
- cooldown: config.cooldown
706
- };
707
- }),
708
- worker: (cap) => Effect.gen(function* () {
709
- const config = yield* WorkerConfig;
710
- return {
711
- intensity: config.intensity,
712
- backoff: cappedBackoff(config.backoffBase, cap),
713
- cooldown: config.cooldown
714
- };
715
- }),
716
- task: (budget) => Effect.gen(function* () {
717
- const config = yield* TaskConfig;
718
- return {
719
- intensity: config.intensity,
720
- backoff: Schedule.exponential(config.backoffBase).pipe(Schedule.jittered, Schedule.upTo(budget)),
721
- cooldown: config.cooldown
722
- };
723
- }),
724
- custom: (policy) => Effect.succeed(policy)
725
- };
726
725
  //#endregion
727
- //#region src/supervisor.ts
728
- const makeSupervisor = (opts, strategy) => ({
726
+ //#region src/supervision-custom.kernel.ts
727
+ const custom = (policy) => Effect.succeed(policy);
728
+ //#endregion
729
+ //#region src/supervision-leader.kernel.ts
730
+ const leader$1 = (config, cap) => Effect.succeed({
731
+ intensity: config.intensity,
732
+ backoff: cappedBackoff(config.backoffBase, cap),
733
+ cooldown: config.cooldown
734
+ });
735
+ //#endregion
736
+ //#region src/supervision-task.kernel.ts
737
+ const task$1 = (config, budget) => Effect.succeed({
738
+ intensity: config.intensity,
739
+ backoff: Schedule.exponential(config.backoffBase).pipe(Schedule.jittered, Schedule.upTo(budget)),
740
+ cooldown: config.cooldown
741
+ });
742
+ //#endregion
743
+ //#region src/supervision-worker.kernel.ts
744
+ const worker$1 = (config, cap) => Effect.succeed({
745
+ intensity: config.intensity,
746
+ backoff: cappedBackoff(config.backoffBase, cap),
747
+ cooldown: config.cooldown
748
+ });
749
+ //#endregion
750
+ //#region src/supervisor-dynamic.kernel.ts
751
+ const dynamic$1 = (opts) => ({
752
+ [DynamicSpecTypeId]: DynamicSpecTypeId,
753
+ name: opts.name,
754
+ child: opts.child,
755
+ maxChildren: opts.maxChildren ?? 1e3
756
+ });
757
+ //#endregion
758
+ //#region src/supervisor-one-for-all.kernel.ts
759
+ const oneForAll$1 = (opts) => ({
729
760
  [SupervisorTypeId]: SupervisorTypeId,
730
761
  name: opts.name,
731
- strategy,
762
+ strategy: "one_for_all",
732
763
  children: opts.children,
733
764
  supervision: opts.supervision,
734
765
  lock: opts.lock,
735
766
  reporter: opts.reporter ?? {}
736
767
  });
737
- const oneForOne = (opts) => makeSupervisor(opts, "one_for_one");
738
- const oneForAll = (opts) => makeSupervisor(opts, "one_for_all");
739
- const restForOne = (opts) => makeSupervisor(opts, "rest_for_one");
740
- const dynamic = (opts) => ({
741
- [DynamicSpecTypeId]: DynamicSpecTypeId,
768
+ //#endregion
769
+ //#region src/supervisor-one-for-one.kernel.ts
770
+ const oneForOne$1 = (opts) => ({
771
+ [SupervisorTypeId]: SupervisorTypeId,
742
772
  name: opts.name,
743
- child: opts.child,
744
- maxChildren: opts.maxChildren ?? 1e3
773
+ strategy: "one_for_one",
774
+ children: opts.children,
775
+ supervision: opts.supervision,
776
+ lock: opts.lock,
777
+ reporter: opts.reporter ?? {}
778
+ });
779
+ //#endregion
780
+ //#region src/supervisor-rest-for-one.kernel.ts
781
+ const restForOne$1 = (opts) => ({
782
+ [SupervisorTypeId]: SupervisorTypeId,
783
+ name: opts.name,
784
+ strategy: "rest_for_one",
785
+ children: opts.children,
786
+ supervision: opts.supervision,
787
+ lock: opts.lock,
788
+ reporter: opts.reporter ?? {}
745
789
  });
746
790
  //#endregion
747
- export { BoundedIntensity, ChildPolicyConfig, Daemon, DaemonReporter, DynamicLimitExceeded, DynamicSpecTypeId, Intensity, IntensityConfig, IntensityTypeId, LeaderConfig, LeaderLock, LeaderLockFromPrimitive, LeaderLockInfraError, LeaderLockNotAcquired, LockPolicyConfig, LockPrimitive, LockPrimitiveError, Supervision, SupervisorTypeId, TaskConfig, TickPolicyConfig, UnboundedIntensity, WorkerConfig, WorkerTypeId, cappedBackoff, dynamic, healthStateGauge, isSupervisor, isWorker, oneForAll, oneForOne, poll, restForOne, run, stream, subscription, supervisor, supervisorChildrenGauge, supervisorExhaustionsCounter, supervisorRestartsCounter, withLeaderLock, worker };
791
+ //#region src/mod.ts
792
+ const poll = (opts) => poll$1(opts);
793
+ const stream = (opts) => stream$1(opts);
794
+ const subscription = (opts) => subscription$1(opts);
795
+ const Daemon = {
796
+ poll,
797
+ stream,
798
+ subscription
799
+ };
800
+ const run = {
801
+ worker,
802
+ supervisor,
803
+ dynamic: dynamic$2
804
+ };
805
+ const leader = (cap) => Effect.flatMap(LeaderConfig, (config) => leader$1(config, cap));
806
+ const task = (budget) => Effect.flatMap(TaskConfig, (config) => task$1(config, budget));
807
+ const supervision = (cap) => Effect.flatMap(WorkerConfig, (config) => worker$1(config, cap));
808
+ const Supervision = {
809
+ leader,
810
+ worker: supervision,
811
+ task,
812
+ custom
813
+ };
814
+ const dynamic = (opts) => dynamic$1(opts);
815
+ const oneForAll = (opts) => oneForAll$1(opts);
816
+ const oneForOne = (opts) => oneForOne$1(opts);
817
+ const restForOne = (opts) => restForOne$1(opts);
818
+ const WithLeaderLockExecutorLive = Layer.effect(WithLeaderLockExecutorDeps, Effect.gen(function* () {
819
+ return { withLock: (yield* LeaderLock).withLock };
820
+ }));
821
+ const SupervisorBodyExecutorLive = Layer.effect(SupervisorBodyExecutorDeps, Effect.gen(function* () {
822
+ const reporter = yield* DaemonReporter;
823
+ return {
824
+ onRestart: reporter.onRestart,
825
+ onExhausted: reporter.onExhausted
826
+ };
827
+ }));
828
+ //#endregion
829
+ export { BoundedIntensity, ChildPolicyConfig, Daemon, DaemonReporter, DynamicLimitExceeded, DynamicSpecTypeId, Intensity, IntensityConfig, LeaderConfig, LeaderLock, LeaderLockFromPrimitive, LeaderLockInfraError, LeaderLockNotAcquired, LockPolicyConfig, LockPrimitive, LockPrimitiveError, Noop, Supervision, SupervisorBodyExecutorDeps, SupervisorBodyExecutorLive, SupervisorTypeId, TaskConfig, TickPolicyConfig, UnboundedIntensity, WithLeaderLockExecutorDeps, WithLeaderLockExecutorLive, WorkerConfig, WorkerTypeId, cappedBackoff, dynamic, healthStateGauge, leader, oneForAll, oneForOne, poll, restForOne, run, stream, subscription, supervision, supervisor, supervisorChildrenGauge, supervisorExhaustionsCounter, supervisorRestartsCounter, task, withLeaderLock, worker };