@effect-agent/platform-cloudflare 0.1.0-beta.112 → 0.1.0-beta.114
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/Alarm.d.mts +37 -12
- package/dist/Alarm.mjs +118 -29
- package/dist/Alarm.mjs.map +1 -1
- package/dist/CloudflareThreadClient.d.mts +8 -8
- package/dist/{ThreadObject-DVxgrU7c.d.mts → ThreadObject-B97Se7j5.d.mts} +33 -33
- package/dist/{ThreadObject-0k-SVpY_.mjs → ThreadObject-BPt5uByD.mjs} +17 -8
- package/dist/ThreadObject-BPt5uByD.mjs.map +1 -0
- package/dist/ThreadObject.d.mts +1 -1
- package/dist/ThreadObject.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/Alarm.ts +247 -46
- package/src/internal/message-delivery.ts +33 -23
- package/dist/ThreadObject-0k-SVpY_.mjs.map +0 -1
package/dist/Alarm.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ import { ThreadProjectionError, ThreadProjectionMaintenance } from "effect-agent
|
|
|
10
10
|
import { WakeScheduler } from "effect-agent/wake-scheduler";
|
|
11
11
|
import { SqlClient } from "effect/unstable/sql/SqlClient";
|
|
12
12
|
declare namespace Alarm_d_exports {
|
|
13
|
-
export { DurableAlarmError, DurableAlarmService, MaintenancePassFailure, MaintenancePassReport, ThreadHostMaintenance, ThreadMaintenance, ThreadMaintenanceFailpoint, ThreadMaintenanceFailpointHandler, ThreadMaintenanceFailpointLocation, ThreadMessageDelivery, ThreadMutationGate, ThreadPublication, ThreadPublicationService, ThreadRecoveryFault, publishCommitted };
|
|
13
|
+
export { DurableAlarmError, DurableAlarmService, MaintenancePassFailure, MaintenancePassReport, ThreadHostMaintenance, ThreadMaintenance, ThreadMaintenanceActivity, ThreadMaintenanceFailpoint, ThreadMaintenanceFailpointHandler, ThreadMaintenanceFailpointLocation, ThreadMessageDelivery, ThreadMutationGate, ThreadPublication, ThreadPublicationService, ThreadRecoveryFault, publishCommitted };
|
|
14
14
|
}
|
|
15
15
|
declare const DurableAlarmError_base: Schema.Class<DurableAlarmError, Schema.TaggedStruct<"DurableAlarmError", {
|
|
16
16
|
readonly operation: Schema.String;
|
|
@@ -114,25 +114,49 @@ declare const ThreadPublication_base: Context.ServiceClass<ThreadPublication, "@
|
|
|
114
114
|
export declare class ThreadPublication extends ThreadPublication_base {
|
|
115
115
|
static readonly layer: Layer.Layer<ThreadPublication, never, never>;
|
|
116
116
|
}
|
|
117
|
+
declare const ThreadMaintenanceActivity_base: Context.ServiceClass<ThreadMaintenanceActivity, "@effect-agent/platform-cloudflare/ThreadMaintenanceActivity", {
|
|
118
|
+
/**
|
|
119
|
+
* Account for one finite selection/dispatch, through joined completion or interruption.
|
|
120
|
+
* Register before reading/claiming work. After dispatch closes the body is not started.
|
|
121
|
+
* Host waves retain their declared allowance from this call; message Claims keep the driver's
|
|
122
|
+
* own deadline. Waiting for notifications belongs outside this bracket.
|
|
123
|
+
*/
|
|
124
|
+
readonly run: <R>(wave: Effect.Effect<void, DurableAlarmError, R>) => Effect.Effect<void, DurableAlarmError, R>;
|
|
125
|
+
/** Acknowledge all initial subscriptions/scans. Composite hosts use `all` below. */
|
|
126
|
+
readonly ready: Effect.Effect<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Acquire an independent scoped subscription before the initial scan and `ready`.
|
|
129
|
+
* The returned wait observes coalesced native scan hints, including those published before
|
|
130
|
+
* its first execution. Each hint requests a current local due-work check.
|
|
131
|
+
*/
|
|
132
|
+
readonly subscribeChanges: Effect.Effect<Effect.Effect<void>, never, Scope.Scope>;
|
|
133
|
+
}>;
|
|
134
|
+
/** Event-local accounting shared by the existing maintenance pumps and native scheduler. */
|
|
135
|
+
export declare class ThreadMaintenanceActivity extends ThreadMaintenanceActivity_base {
|
|
136
|
+
/** Join child pumps; acknowledge the parent only after every child is ready or has exited. */
|
|
137
|
+
static readonly all: <A, E, R>(lanes: readonly Effect.Effect<A, E, R>[]) => Effect.Effect<readonly A[], E, R | ThreadMaintenanceActivity>;
|
|
138
|
+
}
|
|
117
139
|
/**
|
|
118
140
|
* Host-assembled native message recovery. The driver bounds each actual Claim and persists its
|
|
119
141
|
* timeout/retry before this pump returns. Do not add a second timer starting at batch selection:
|
|
120
142
|
* local Claim setup may take time, and expiration still owes the driver's local retry commit.
|
|
121
143
|
*/
|
|
122
144
|
export declare const ThreadMessageDelivery: Context.Reference<{
|
|
123
|
-
readonly drainUntil: (dispatchClosed: Effect.Effect<void>, dispatchUntil: DateTime.Utc) => Effect.Effect<void, DurableAlarmError, Scope.Scope>;
|
|
145
|
+
readonly drainUntil: (dispatchClosed: Effect.Effect<void>, dispatchUntil: DateTime.Utc) => Effect.Effect<void, DurableAlarmError, Scope.Scope | ThreadMaintenanceActivity>;
|
|
124
146
|
readonly pendingDeadline: Effect.Effect<Option.Option<number>, DurableAlarmError>;
|
|
125
147
|
}>;
|
|
126
148
|
/**
|
|
127
149
|
* Application obligations sharing this Object's alarm. Admit one initial external wave even on
|
|
128
|
-
* a caught-up pass, then respond to wakes
|
|
129
|
-
*
|
|
130
|
-
*
|
|
150
|
+
* a caught-up pass, then respond to wakes and ThreadMaintenanceActivity.subscribeChanges until
|
|
151
|
+
* dispatchClosed. Yield the event's ThreadMaintenanceActivity to bracket each finite lane with
|
|
152
|
+
* run and acknowledge initial setup with ready.
|
|
153
|
+
* Passive subscriptions do not count as active work. Closure stops both new waves and native
|
|
154
|
+
* Attempts; local admission/control subscriptions belong to the event Scope until teardown.
|
|
131
155
|
* No deadline sleeps or automatic retry loops. Return after already-admitted waves finish.
|
|
132
156
|
*
|
|
133
157
|
* Declare a finite whole-wave allowance (1..300000ms): maximum for parallel lanes, sum for
|
|
134
158
|
* sequential operations. Admit a wave only if its allowance fits before dispatchUntil. Later
|
|
135
|
-
* arrivals cannot renew
|
|
159
|
+
* arrivals cannot renew an admitted wave's allowance. Maintenance bounds each registered wave,
|
|
136
160
|
* interrupts and joins event Scope, then reads local deadlines under the mutation gate.
|
|
137
161
|
*
|
|
138
162
|
* Setup and pendingDeadline are bounded local operations. Persist claims/envelopes before
|
|
@@ -143,7 +167,7 @@ export declare const ThreadMessageDelivery: Context.Reference<{
|
|
|
143
167
|
*/
|
|
144
168
|
export declare const ThreadHostMaintenance: Context.Reference<{
|
|
145
169
|
readonly dispatchTimeoutMillis: number;
|
|
146
|
-
readonly drainUntil: (dispatchClosed: Effect.Effect<void>, dispatchUntil: DateTime.Utc) => Effect.Effect<void, DurableAlarmError, Scope.Scope>;
|
|
170
|
+
readonly drainUntil: (dispatchClosed: Effect.Effect<void>, dispatchUntil: DateTime.Utc) => Effect.Effect<void, DurableAlarmError, Scope.Scope | ThreadMaintenanceActivity>;
|
|
147
171
|
readonly pendingDeadline: Effect.Effect<Option.Option<number>, DurableAlarmError>;
|
|
148
172
|
}>;
|
|
149
173
|
/** @internal A committed source operation must not become a failed operation because delivery failed. */
|
|
@@ -216,11 +240,12 @@ declare const ThreadMaintenance_base: Context.ServiceClass<ThreadMaintenance, "@
|
|
|
216
240
|
* 1. Prearm before any work. A caught-up native step uses the O(1) generation record without
|
|
217
241
|
* recovery, ledger scans or canonical-history reads.
|
|
218
242
|
* 2. Reconcile before each head Attempt, then checkpoint only the observed generation. A racing
|
|
219
|
-
* producer keeps its
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
243
|
+
* producer keeps its generation dirty and immediately eligible. Quiescent native retries
|
|
244
|
+
* retain their durable backoff.
|
|
245
|
+
* 3. Keep native and delivery admission open together while finite waves remain active, so
|
|
246
|
+
* fresh replies and abort controls can progress during unrelated cleanup. Close atomically
|
|
247
|
+
* at quiescence, or at the original ten-minute yield deadline, before retiring listeners.
|
|
248
|
+
* 4. Native message delivery retains its driver-owned Claim deadline. Host/backfill waves are
|
|
224
249
|
* bounded independently; incoming native work never restarts or cancels their attempts.
|
|
225
250
|
* Auxiliary failures are reported after the current native opportunity.
|
|
226
251
|
* 5. Close every event resource before the final gated deadline snapshot and alarm decision.
|
package/dist/Alarm.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
|
2
2
|
import { DurableObjectContext } from "./CloudflareBindings.mjs";
|
|
3
3
|
import { AuxiliaryDispatchMillis, CloudflareDurableRuntimeConfig } from "./CloudflareConfig.mjs";
|
|
4
4
|
import { r as safeCauseMessage } from "./boundary-BguazVkh.mjs";
|
|
5
|
-
import { Cause, Clock, Context, DateTime, Deferred, Effect, Exit, Fiber, Layer, Option, Random, Ref, Result, Schema, Scope, Semaphore, Stream, Struct } from "effect";
|
|
5
|
+
import { Cause, Clock, Context, DateTime, Deferred, Effect, Exit, Fiber, Layer, Option, PubSub, Random, Ref, Result, Schema, Scope, Semaphore, Stream, Struct } from "effect";
|
|
6
6
|
import "effect-agent/agent-registration";
|
|
7
7
|
import { DurableAgentRuntime, DurableRuntimeConfig, RecoveryBlocked, RecoveryFailure, RecoverySweepResult, isolateRecovery } from "effect-agent/durable-agent-runtime";
|
|
8
8
|
import { SubmissionId, ThreadId } from "effect-agent/identifiers";
|
|
@@ -18,6 +18,7 @@ var Alarm_exports = /* @__PURE__ */ __exportAll({
|
|
|
18
18
|
MaintenancePassReport: () => MaintenancePassReport,
|
|
19
19
|
ThreadHostMaintenance: () => ThreadHostMaintenance,
|
|
20
20
|
ThreadMaintenance: () => ThreadMaintenance,
|
|
21
|
+
ThreadMaintenanceActivity: () => ThreadMaintenanceActivity,
|
|
21
22
|
ThreadMaintenanceFailpoint: () => ThreadMaintenanceFailpoint,
|
|
22
23
|
ThreadMessageDelivery: () => ThreadMessageDelivery,
|
|
23
24
|
ThreadMutationGate: () => ThreadMutationGate,
|
|
@@ -111,6 +112,27 @@ var ThreadPublication = class extends Context.Service()("@effect-agent/platform-
|
|
|
111
112
|
pendingDeadline: Effect.succeed(Option.none())
|
|
112
113
|
});
|
|
113
114
|
};
|
|
115
|
+
/** Event-local accounting shared by the existing maintenance pumps and native scheduler. */
|
|
116
|
+
var ThreadMaintenanceActivity = class ThreadMaintenanceActivity extends Context.Service()("@effect-agent/platform-cloudflare/ThreadMaintenanceActivity") {
|
|
117
|
+
/** Join child pumps; acknowledge the parent only after every child is ready or has exited. */
|
|
118
|
+
static all = Effect.fnUntraced(function* (lanes) {
|
|
119
|
+
const activity = yield* ThreadMaintenanceActivity;
|
|
120
|
+
let remaining = lanes.length;
|
|
121
|
+
if (remaining === 0) return yield* activity.ready.pipe(Effect.as([]));
|
|
122
|
+
return yield* Effect.forEach(lanes, (lane) => {
|
|
123
|
+
let ready = false;
|
|
124
|
+
const child = {
|
|
125
|
+
...activity,
|
|
126
|
+
ready: Effect.suspend(() => {
|
|
127
|
+
if (ready) return Effect.void;
|
|
128
|
+
ready = true;
|
|
129
|
+
return --remaining === 0 ? activity.ready : Effect.void;
|
|
130
|
+
}).pipe(Effect.uninterruptible)
|
|
131
|
+
};
|
|
132
|
+
return lane.pipe(Effect.provideService(ThreadMaintenanceActivity, child), Effect.onExit(() => child.ready));
|
|
133
|
+
}, { concurrency: "unbounded" });
|
|
134
|
+
});
|
|
135
|
+
};
|
|
114
136
|
/**
|
|
115
137
|
* Host-assembled native message recovery. The driver bounds each actual Claim and persists its
|
|
116
138
|
* timeout/retry before this pump returns. Do not add a second timer starting at batch selection:
|
|
@@ -122,14 +144,16 @@ const ThreadMessageDelivery = Context.Reference("@effect-agent/platform-cloudfla
|
|
|
122
144
|
}) });
|
|
123
145
|
/**
|
|
124
146
|
* Application obligations sharing this Object's alarm. Admit one initial external wave even on
|
|
125
|
-
* a caught-up pass, then respond to wakes
|
|
126
|
-
*
|
|
127
|
-
*
|
|
147
|
+
* a caught-up pass, then respond to wakes and ThreadMaintenanceActivity.subscribeChanges until
|
|
148
|
+
* dispatchClosed. Yield the event's ThreadMaintenanceActivity to bracket each finite lane with
|
|
149
|
+
* run and acknowledge initial setup with ready.
|
|
150
|
+
* Passive subscriptions do not count as active work. Closure stops both new waves and native
|
|
151
|
+
* Attempts; local admission/control subscriptions belong to the event Scope until teardown.
|
|
128
152
|
* No deadline sleeps or automatic retry loops. Return after already-admitted waves finish.
|
|
129
153
|
*
|
|
130
154
|
* Declare a finite whole-wave allowance (1..300000ms): maximum for parallel lanes, sum for
|
|
131
155
|
* sequential operations. Admit a wave only if its allowance fits before dispatchUntil. Later
|
|
132
|
-
* arrivals cannot renew
|
|
156
|
+
* arrivals cannot renew an admitted wave's allowance. Maintenance bounds each registered wave,
|
|
133
157
|
* interrupts and joins event Scope, then reads local deadlines under the mutation gate.
|
|
134
158
|
*
|
|
135
159
|
* Setup and pendingDeadline are bounded local operations. Persist claims/envelopes before
|
|
@@ -285,11 +309,12 @@ var ThreadMutationGate = class ThreadMutationGate extends Context.Service()("@ef
|
|
|
285
309
|
* 1. Prearm before any work. A caught-up native step uses the O(1) generation record without
|
|
286
310
|
* recovery, ledger scans or canonical-history reads.
|
|
287
311
|
* 2. Reconcile before each head Attempt, then checkpoint only the observed generation. A racing
|
|
288
|
-
* producer keeps its
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
312
|
+
* producer keeps its generation dirty and immediately eligible. Quiescent native retries
|
|
313
|
+
* retain their durable backoff.
|
|
314
|
+
* 3. Keep native and delivery admission open together while finite waves remain active, so
|
|
315
|
+
* fresh replies and abort controls can progress during unrelated cleanup. Close atomically
|
|
316
|
+
* at quiescence, or at the original ten-minute yield deadline, before retiring listeners.
|
|
317
|
+
* 4. Native message delivery retains its driver-owned Claim deadline. Host/backfill waves are
|
|
293
318
|
* bounded independently; incoming native work never restarts or cancels their attempts.
|
|
294
319
|
* Auxiliary failures are reported after the current native opportunity.
|
|
295
320
|
* 5. Close every event resource before the final gated deadline snapshot and alarm decision.
|
|
@@ -608,13 +633,15 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
608
633
|
yield* failpoint.hit("maintenance:checkpoint:before");
|
|
609
634
|
const nextAttemptAt = yield* mutations.withSnapshot((active) => runTransaction("checkpoint native maintenance", () => ctx.storage.transaction(async (transaction) => {
|
|
610
635
|
const { state } = await readMaintenanceState(transaction);
|
|
611
|
-
const
|
|
636
|
+
const mutationOverlap = observation.activeAtStart > 0 || started.activeAtStart > 0 || active > 0;
|
|
637
|
+
const processed = autonomous || mutationOverlap ? state.processed : state.processed > observation.generation ? state.processed : observation.generation;
|
|
638
|
+
const canBackoff = !mutationOverlap && state.dirty === started.generation;
|
|
612
639
|
const next = ThreadMaintenanceState.make({
|
|
613
640
|
...Struct.omit(state, ["retry"]),
|
|
614
641
|
processed,
|
|
615
642
|
nonterminal: remaining.length,
|
|
616
643
|
bindingRetries: (state.bindingRetries ?? []).filter((retry) => remaining.some((row) => row.submissionId === retry.submissionId)),
|
|
617
|
-
...autonomous && !progressed ? { retry: MaintenanceRetry.make({
|
|
644
|
+
...autonomous && !progressed && canBackoff ? { retry: MaintenanceRetry.make({
|
|
618
645
|
generation: started.generation,
|
|
619
646
|
notBefore: now + delay,
|
|
620
647
|
nativeOnly: true,
|
|
@@ -622,8 +649,8 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
622
649
|
}) } : {}
|
|
623
650
|
});
|
|
624
651
|
await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(next));
|
|
625
|
-
if (autonomous) return
|
|
626
|
-
return
|
|
652
|
+
if (autonomous) return now + (canBackoff ? delay : minimumAlarmDelay);
|
|
653
|
+
return mutationOverlap || next.dirty > next.processed ? now + minimumAlarmDelay : void 0;
|
|
627
654
|
})));
|
|
628
655
|
yield* failpoint.hit("maintenance:checkpoint:after");
|
|
629
656
|
return {
|
|
@@ -637,6 +664,47 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
637
664
|
const notified = (yield* Stream.toPull(wakes.wakes)).pipe(Effect.asVoid, Effect.catch(() => Effect.never));
|
|
638
665
|
const started = yield* beginNative(observed);
|
|
639
666
|
const auxiliaryScope = yield* Effect.acquireRelease(Scope.make("parallel"), (scope, exit) => Scope.close(scope, exit));
|
|
667
|
+
const dispatchClosed = yield* Deferred.make();
|
|
668
|
+
const stopDispatch = Deferred.await(dispatchClosed);
|
|
669
|
+
const checks = yield* PubSub.sliding(1);
|
|
670
|
+
yield* Effect.addFinalizer(() => PubSub.shutdown(checks));
|
|
671
|
+
let dispatchOpen = true;
|
|
672
|
+
let activityChanged = yield* Deferred.make();
|
|
673
|
+
const signalActivity = Effect.suspend(() => Deferred.succeed(activityChanged, void 0));
|
|
674
|
+
const closeDispatch = Effect.sync(() => {
|
|
675
|
+
dispatchOpen = false;
|
|
676
|
+
}).pipe(Effect.andThen(Deferred.succeed(dispatchClosed, void 0)));
|
|
677
|
+
const makeActivity = Effect.fnUntraced(function* (allowance) {
|
|
678
|
+
const initialized = yield* Deferred.make();
|
|
679
|
+
let active = 0;
|
|
680
|
+
let failed = false;
|
|
681
|
+
return {
|
|
682
|
+
activity: {
|
|
683
|
+
ready: Deferred.succeed(initialized, void 0).pipe(Effect.andThen(signalActivity), Effect.asVoid, Effect.uninterruptible),
|
|
684
|
+
subscribeChanges: PubSub.subscribe(checks).pipe(Effect.map(PubSub.take)),
|
|
685
|
+
run: (wave) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
686
|
+
if (!dispatchOpen) return false;
|
|
687
|
+
active++;
|
|
688
|
+
return true;
|
|
689
|
+
}), (admitted) => !admitted ? Effect.void : (allowance === void 0 ? wave : wave.pipe(Effect.timeoutOrElse({
|
|
690
|
+
duration: allowance,
|
|
691
|
+
orElse: () => DurableAlarmError.make({
|
|
692
|
+
operation: "host dispatch allowance",
|
|
693
|
+
message: "The admitted host wave exceeded its allowance; durable work remains pending"
|
|
694
|
+
})
|
|
695
|
+
}))).pipe(Effect.onExit((exit) => Effect.sync(() => {
|
|
696
|
+
if (Exit.isFailure(exit)) failed = true;
|
|
697
|
+
}))), (admitted) => Effect.sync(() => {
|
|
698
|
+
if (admitted) active--;
|
|
699
|
+
}).pipe(Effect.andThen(signalActivity)))
|
|
700
|
+
},
|
|
701
|
+
initialized: Deferred.await(initialized),
|
|
702
|
+
quiet: () => active === 0 && Deferred.isDoneUnsafe(initialized),
|
|
703
|
+
failed: () => failed
|
|
704
|
+
};
|
|
705
|
+
});
|
|
706
|
+
const messageActivity = yield* makeActivity();
|
|
707
|
+
const hostActivity = yield* makeActivity(host.dispatchTimeoutMillis);
|
|
640
708
|
const recovery = {
|
|
641
709
|
queue: yield* Deferred.make(),
|
|
642
710
|
pending: /* @__PURE__ */ new Set(),
|
|
@@ -664,18 +732,23 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
664
732
|
yield* wakes.notify(threadId);
|
|
665
733
|
}
|
|
666
734
|
}), auxiliaryScope);
|
|
667
|
-
const
|
|
668
|
-
const stopDispatch = Deferred.await(dispatchClosed);
|
|
669
|
-
const deliveryFiber = yield* Effect.forkIn(Scope.provide(auxiliaryScope)(messages.drainUntil(stopDispatch, dispatchUntil)), auxiliaryScope);
|
|
735
|
+
const deliveryFiber = yield* Effect.forkIn(Scope.provide(auxiliaryScope)(messages.drainUntil(stopDispatch, dispatchUntil).pipe(Effect.provideService(ThreadMaintenanceActivity, messageActivity.activity), Effect.onExit(() => messageActivity.activity.ready))), auxiliaryScope);
|
|
670
736
|
const hostFiber = yield* Effect.forkIn(Scope.provide(auxiliaryScope)(Effect.gen(function* () {
|
|
671
737
|
yield* Schema.decodeEffect(AuxiliaryDispatchMillis)(host.dispatchTimeoutMillis).pipe(Effect.mapError((cause) => DurableAlarmError.make({
|
|
672
738
|
operation: "host dispatch allowance",
|
|
673
739
|
message: "Declare an integer whole-wave allowance between 1 and 300000 milliseconds",
|
|
674
740
|
cause
|
|
675
741
|
})));
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
742
|
+
const initialization = hostActivity.initialized.pipe(Effect.timeoutOrElse({
|
|
743
|
+
duration: host.dispatchTimeoutMillis,
|
|
744
|
+
orElse: () => DurableAlarmError.make({
|
|
745
|
+
operation: "host initialization",
|
|
746
|
+
message: "The host did not account for initial maintenance before its allowance; durable work remains pending"
|
|
747
|
+
})
|
|
748
|
+
}), Effect.andThen(Effect.never));
|
|
749
|
+
yield* Effect.raceFirst(host.drainUntil(stopDispatch, dispatchUntil).pipe(Effect.provideService(ThreadMaintenanceActivity, hostActivity.activity)), initialization);
|
|
750
|
+
}).pipe(Effect.onExit(() => hostActivity.activity.ready))), auxiliaryScope);
|
|
751
|
+
const backfill = yield* Effect.forkIn(drainDue.pipe(Effect.provideService(ThreadProjectionMaintenance, projection), Effect.timeoutOption(config.projectionDispatchTimeoutMillis), Effect.onExit(() => signalActivity)), auxiliaryScope);
|
|
679
752
|
let result = yield* advance(started, yieldAfter, observed, recovery);
|
|
680
753
|
recovery.started = true;
|
|
681
754
|
yield* Deferred.succeed(recovery.queue, []);
|
|
@@ -694,9 +767,9 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
694
767
|
backfill,
|
|
695
768
|
recoveryFiber
|
|
696
769
|
]));
|
|
697
|
-
const auxiliaryPending = () => deliveryFiber.pollUnsafe() === void 0 || hostFiber.pollUnsafe() === void 0 || backfill.pollUnsafe() === void 0 || recoveryFiber.pollUnsafe() === void 0;
|
|
698
770
|
while (true) {
|
|
699
771
|
const recoveryFinished = recoveryFiber.pollUnsafe() !== void 0;
|
|
772
|
+
const retiredExit = retired.pollUnsafe();
|
|
700
773
|
if (recoveryFinished) {
|
|
701
774
|
if (recovery.needsCheckpoint) {
|
|
702
775
|
yield* Fiber.join(recoveryFiber);
|
|
@@ -704,27 +777,43 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
704
777
|
if (result.phase === "actionable") phase = "actionable";
|
|
705
778
|
settled += result.settled;
|
|
706
779
|
recovery.needsCheckpoint = false;
|
|
780
|
+
yield* PubSub.publish(checks, void 0);
|
|
707
781
|
}
|
|
708
|
-
yield* Deferred.succeed(dispatchClosed, void 0);
|
|
709
782
|
}
|
|
710
|
-
if (
|
|
783
|
+
if (retiredExit !== void 0 && Exit.isFailure(retiredExit)) break;
|
|
784
|
+
if (recoveryFinished && backfill.pollUnsafe() !== void 0 && messageActivity.quiet() && hostActivity.quiet()) {
|
|
785
|
+
const now = yield* Clock.currentTimeMillis;
|
|
786
|
+
const messageDeadline = yield* messages.pendingDeadline;
|
|
787
|
+
const hostDeadline = yield* host.pendingDeadline;
|
|
788
|
+
const messageDue = deliveryFiber.pollUnsafe() === void 0 && !messageActivity.failed() && Option.isSome(messageDeadline) && messageDeadline.value <= now;
|
|
789
|
+
const hostDue = hostFiber.pollUnsafe() === void 0 && !hostActivity.failed() && now + host.dispatchTimeoutMillis <= DateTime.toEpochMillis(dispatchUntil) && Option.isSome(hostDeadline) && hostDeadline.value <= now;
|
|
790
|
+
if (yield* Effect.sync(() => {
|
|
791
|
+
if (messageDue || hostDue || !messageActivity.quiet() || !hostActivity.quiet()) return false;
|
|
792
|
+
dispatchOpen = false;
|
|
793
|
+
return true;
|
|
794
|
+
})) break;
|
|
795
|
+
yield* PubSub.publish(checks, void 0);
|
|
796
|
+
}
|
|
711
797
|
const now = yield* Clock.currentTimeMillis;
|
|
712
798
|
const until = DateTime.toEpochMillis(yieldAfter);
|
|
713
799
|
if (now >= until) break;
|
|
714
800
|
const next = Math.min(result.nextAttemptAt ?? Infinity, now + config.wakeScanInterval, until);
|
|
715
801
|
const recoveryDone = recoveryFinished ? Effect.never : Fiber.await(recoveryFiber);
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (
|
|
802
|
+
const retirementDone = retiredExit === void 0 ? Fiber.await(retired) : Effect.never;
|
|
803
|
+
const changed = activityChanged;
|
|
804
|
+
const ready = yield* Effect.raceFirst(Effect.raceFirst(notified, Effect.sleep(Math.max(0, next - now))).pipe(Effect.as("native")), Effect.raceFirst(recoveryDone.pipe(Effect.as("recovery")), Effect.raceFirst(retirementDone.pipe(Effect.as("retired")), Deferred.await(changed).pipe(Effect.as("activity")))));
|
|
805
|
+
if (ready === "recovery" || ready === "retired") continue;
|
|
806
|
+
if (ready === "activity") activityChanged = yield* Deferred.make();
|
|
720
807
|
if ((yield* Clock.currentTimeMillis) >= until) break;
|
|
808
|
+
if (ready === "native") yield* PubSub.publish(checks, void 0);
|
|
721
809
|
const awakened = yield* beginNative(observed);
|
|
722
810
|
result = yield* advance(awakened, yieldAfter, observed, recovery);
|
|
723
811
|
if (result.phase === "actionable") phase = "actionable";
|
|
724
812
|
settled += result.settled;
|
|
725
813
|
observed.nativeOnly = false;
|
|
814
|
+
if (result.settled > 0) yield* PubSub.publish(checks, void 0);
|
|
726
815
|
}
|
|
727
|
-
yield*
|
|
816
|
+
yield* closeDispatch;
|
|
728
817
|
yield* Fiber.join(retired);
|
|
729
818
|
if (recovery.needsCheckpoint) {
|
|
730
819
|
result = yield* advance(started, yieldAfter, observed, recovery, false);
|
|
@@ -786,6 +875,6 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
|
|
|
786
875
|
}));
|
|
787
876
|
};
|
|
788
877
|
//#endregion
|
|
789
|
-
export { DurableAlarmError, DurableAlarmService, MaintenancePassReport, ThreadHostMaintenance, ThreadMaintenance, ThreadMaintenanceFailpoint, ThreadMessageDelivery, ThreadMutationGate, ThreadPublication, ThreadRecoveryFault, publishCommitted, Alarm_exports as t };
|
|
878
|
+
export { DurableAlarmError, DurableAlarmService, MaintenancePassReport, ThreadHostMaintenance, ThreadMaintenance, ThreadMaintenanceActivity, ThreadMaintenanceFailpoint, ThreadMessageDelivery, ThreadMutationGate, ThreadPublication, ThreadRecoveryFault, publishCommitted, Alarm_exports as t };
|
|
790
879
|
|
|
791
880
|
//# sourceMappingURL=Alarm.mjs.map
|