@yielded/agent-platform-cloudflare 0.1.0-beta.175 → 0.1.0-beta.176
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-B44efvB1.mjs → Alarm-7uipp6LW.mjs} +45 -44
- package/dist/Alarm-7uipp6LW.mjs.map +1 -0
- package/dist/Alarm.mjs +1 -1
- package/dist/CloudflareScheduling.mjs +2 -2
- package/dist/CloudflareSubscriptions.mjs +2 -2
- package/dist/{CloudflareThreadClient-Ai3MTs3X.mjs → CloudflareThreadClient-bA3lGA_2.mjs} +2 -2
- package/dist/{CloudflareThreadClient-Ai3MTs3X.mjs.map → CloudflareThreadClient-bA3lGA_2.mjs.map} +1 -1
- package/dist/CloudflareThreadClient.mjs +1 -1
- package/dist/{ThreadObject-DGvlHWYi.mjs → ThreadObject-SNcCsrS2.mjs} +15 -12
- package/dist/ThreadObject-SNcCsrS2.mjs.map +1 -0
- package/dist/ThreadObject.mjs +1 -1
- package/dist/WakeScheduler.mjs +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{prepared-admission-DYdffQ8K.mjs → prepared-admission-BvMiFR41.mjs} +2 -2
- package/dist/{prepared-admission-DYdffQ8K.mjs.map → prepared-admission-BvMiFR41.mjs.map} +1 -1
- package/package.json +1 -1
- package/src/Alarm.ts +84 -85
- package/src/internal/layers.ts +69 -48
- package/dist/Alarm-B44efvB1.mjs.map +0 -1
- package/dist/ThreadObject-DGvlHWYi.mjs.map +0 -1
package/src/Alarm.ts
CHANGED
|
@@ -217,7 +217,7 @@ type MaintenanceCheckpoint = {
|
|
|
217
217
|
readonly mutations: Parameters<
|
|
218
218
|
Parameters<ThreadMaintenanceAlarm["Service"]["transaction"]>[0]
|
|
219
219
|
>[0];
|
|
220
|
-
readonly
|
|
220
|
+
readonly isActive: (fiber: Fiber.Fiber<unknown, unknown>) => boolean;
|
|
221
221
|
};
|
|
222
222
|
|
|
223
223
|
const CurrentCheckpoint = Context.Reference<MaintenanceCheckpoint | undefined>(
|
|
@@ -232,31 +232,27 @@ const makeAlarmOperation = Effect.gen(function* () {
|
|
|
232
232
|
const { ctx } = yield* DurableObjectContext;
|
|
233
233
|
const queue = DueQueue.make(ctx.storage);
|
|
234
234
|
|
|
235
|
-
const transaction
|
|
235
|
+
const transaction = <A, E, R>(
|
|
236
|
+
body: (owner: Fiber.Fiber<unknown, unknown>) => Effect.Effect<A, E, R>,
|
|
237
|
+
): Effect.Effect<A, E | SqlError, R> =>
|
|
236
238
|
alarms
|
|
237
239
|
.transaction(
|
|
238
240
|
(mutations) =>
|
|
239
241
|
Effect.withFiber((owner) => {
|
|
240
242
|
let active = true;
|
|
241
243
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
operation: "enroll maintenance source",
|
|
248
|
-
message: "Source intent requires its active transaction callback's fiber",
|
|
249
|
-
}),
|
|
250
|
-
),
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
return body.pipe(
|
|
254
|
-
Effect.provideService(CurrentCheckpoint, { mutations, requireActive }),
|
|
255
|
-
Effect.ensuring(
|
|
256
|
-
Effect.sync(() => {
|
|
257
|
-
active = false;
|
|
244
|
+
return Effect.onExitPrimitive(
|
|
245
|
+
body(owner).pipe(
|
|
246
|
+
Effect.provideService(CurrentCheckpoint, {
|
|
247
|
+
mutations,
|
|
248
|
+
isActive: (fiber) => active && fiber === owner,
|
|
258
249
|
}),
|
|
259
250
|
),
|
|
251
|
+
() => {
|
|
252
|
+
active = false;
|
|
253
|
+
|
|
254
|
+
return undefined;
|
|
255
|
+
},
|
|
260
256
|
);
|
|
261
257
|
}),
|
|
262
258
|
{ sqlClient: sql },
|
|
@@ -276,7 +272,9 @@ const makeAlarmOperation = Effect.gen(function* () {
|
|
|
276
272
|
);
|
|
277
273
|
|
|
278
274
|
const withTransaction = <A, E, R>(body: Effect.Effect<A, E, R>) =>
|
|
279
|
-
Effect.
|
|
275
|
+
Effect.withFiber((fiber) => {
|
|
276
|
+
const ambient = Context.getOption(fiber.context, sql.transactionService);
|
|
277
|
+
|
|
280
278
|
if (ambient._tag === "Some" && !DueQueue.ownsTransaction(ctx.storage, ambient.value[1]))
|
|
281
279
|
return Effect.fail(
|
|
282
280
|
SqlError.make({
|
|
@@ -287,53 +285,53 @@ const makeAlarmOperation = Effect.gen(function* () {
|
|
|
287
285
|
}),
|
|
288
286
|
}),
|
|
289
287
|
);
|
|
288
|
+
let frame: ReturnType<typeof queue.begin> | undefined;
|
|
290
289
|
|
|
291
290
|
return Effect.uninterruptibleMask((restore) =>
|
|
292
|
-
Effect.
|
|
293
|
-
|
|
291
|
+
Effect.onExitPrimitive(
|
|
292
|
+
transaction((owner) => {
|
|
293
|
+
const current = Context.getOption(owner.context, sql.transactionService);
|
|
294
294
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
295
|
+
if (current._tag === "None")
|
|
296
|
+
return SqlError.make({
|
|
297
|
+
reason: UnknownError.make({
|
|
298
|
+
operation: "begin maintenance source transaction",
|
|
299
|
+
message: "SQL transaction unavailable",
|
|
300
|
+
cause: "SQL transaction unavailable",
|
|
301
|
+
}),
|
|
302
|
+
});
|
|
303
|
+
const started = queue.begin(current.value[1]);
|
|
304
|
+
|
|
305
|
+
frame = started;
|
|
306
|
+
|
|
307
|
+
return Effect.flatMap(restore(body), (value) =>
|
|
308
|
+
Effect.try({
|
|
309
|
+
try: () => {
|
|
310
|
+
queue.flush(started);
|
|
311
|
+
|
|
312
|
+
return value;
|
|
313
|
+
},
|
|
314
|
+
catch: (cause) =>
|
|
315
|
+
SqlError.make({
|
|
300
316
|
reason: UnknownError.make({
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}),
|
|
305
|
-
});
|
|
306
|
-
frame = queue.begin(transaction.value[1]);
|
|
307
|
-
}),
|
|
308
|
-
).pipe(
|
|
309
|
-
Effect.andThen(restore(body)),
|
|
310
|
-
Effect.tap(() =>
|
|
311
|
-
Effect.try({
|
|
312
|
-
try: () => {
|
|
313
|
-
if (frame !== undefined) queue.flush(frame);
|
|
314
|
-
},
|
|
315
|
-
catch: (cause) =>
|
|
316
|
-
SqlError.make({
|
|
317
|
-
reason: UnknownError.make({
|
|
318
|
-
cause,
|
|
319
|
-
operation: "flush maintenance due queue",
|
|
320
|
-
message: "Maintenance intent could not commit",
|
|
321
|
-
}),
|
|
317
|
+
cause,
|
|
318
|
+
operation: "flush maintenance due queue",
|
|
319
|
+
message: "Maintenance intent could not commit",
|
|
322
320
|
}),
|
|
323
|
-
|
|
324
|
-
),
|
|
325
|
-
),
|
|
326
|
-
).pipe(
|
|
327
|
-
Effect.onExit((exit) =>
|
|
328
|
-
Effect.sync(() => {
|
|
329
|
-
if (frame !== undefined) queue.finish(frame, Exit.isSuccess(exit));
|
|
321
|
+
}),
|
|
330
322
|
}),
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
323
|
+
);
|
|
324
|
+
}),
|
|
325
|
+
(exit) => {
|
|
326
|
+
if (frame !== undefined) queue.finish(frame, Exit.isSuccess(exit));
|
|
327
|
+
|
|
328
|
+
return undefined;
|
|
329
|
+
},
|
|
330
|
+
).pipe(
|
|
331
|
+
// A released permit can resume another transaction. Do not auto-yield
|
|
332
|
+
// between the driver's settlement and removing this transaction's frame.
|
|
333
|
+
Effect.provideService(Scheduler.PreventSchedulerYield, true),
|
|
334
|
+
),
|
|
337
335
|
);
|
|
338
336
|
}).pipe(Effect.provideService(SqlClient, sql));
|
|
339
337
|
|
|
@@ -352,32 +350,33 @@ const makeAlarmOperation = Effect.gen(function* () {
|
|
|
352
350
|
}),
|
|
353
351
|
);
|
|
354
352
|
|
|
355
|
-
|
|
356
|
-
Effect.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
353
|
+
if (!tx.isActive(fiber))
|
|
354
|
+
return Effect.fail(
|
|
355
|
+
DurableAlarmError.make({
|
|
356
|
+
operation: "enroll maintenance source",
|
|
357
|
+
message: "Source intent requires its active transaction callback's fiber",
|
|
358
|
+
}),
|
|
359
|
+
);
|
|
360
360
|
|
|
361
|
-
|
|
362
|
-
at: (at) => {
|
|
363
|
-
checkpoint = tx.mutations.scheduleAlarm(maintenanceAlarmInput(at));
|
|
364
|
-
},
|
|
365
|
-
earlier: (at) => {
|
|
366
|
-
checkpoint = tx.mutations.scheduleAlarmEarlier(maintenanceAlarmInput(at));
|
|
367
|
-
},
|
|
368
|
-
cancel: () => {
|
|
369
|
-
checkpoint = tx.mutations.cancelAlarm(maintenanceAlarmRef);
|
|
370
|
-
},
|
|
371
|
-
};
|
|
361
|
+
let checkpoint: ReturnType<DurableObjectAlarm.AlarmScheduler["scheduleAlarm"]> = Effect.void;
|
|
372
362
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
363
|
+
const intent: CheckpointIntent = {
|
|
364
|
+
at: (at) => {
|
|
365
|
+
checkpoint = tx.mutations.scheduleAlarm(maintenanceAlarmInput(at));
|
|
366
|
+
},
|
|
367
|
+
earlier: (at) => {
|
|
368
|
+
checkpoint = tx.mutations.scheduleAlarmEarlier(maintenanceAlarmInput(at));
|
|
369
|
+
},
|
|
370
|
+
cancel: () => {
|
|
371
|
+
checkpoint = tx.mutations.cancelAlarm(maintenanceAlarmRef);
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// The SQL/alarm callback already owns the native transaction; KV uses the same storage.
|
|
376
|
+
return Effect.tryPromise({
|
|
377
|
+
try: () => execute(ctx.storage, intent),
|
|
378
|
+
catch: alarmFailure(operation),
|
|
379
|
+
}).pipe(Effect.tap(() => checkpoint));
|
|
381
380
|
});
|
|
382
381
|
|
|
383
382
|
return Effect.withFiber((fiber) => {
|
|
@@ -388,7 +387,7 @@ const makeAlarmOperation = Effect.gen(function* () {
|
|
|
388
387
|
|
|
389
388
|
// Preserve eager writes and invalidation for an unwrapped host SQL transaction.
|
|
390
389
|
return ambient._tag === "Some" && !DueQueue.buffering(ctx.storage)
|
|
391
|
-
? transaction(commit).pipe(
|
|
390
|
+
? transaction(() => commit).pipe(
|
|
392
391
|
Effect.ensuring(Effect.sync(() => DueQueue.invalidate(ctx.storage))),
|
|
393
392
|
)
|
|
394
393
|
: withTransaction(commit);
|
package/src/internal/layers.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { submissionLedgerLayer } from "@yielded/agent-storage-cloudflare/do-submission-ledger";
|
|
8
8
|
import {
|
|
9
9
|
threadStoreLayer,
|
|
10
|
+
journalLayer,
|
|
10
11
|
storageConfigLayer,
|
|
11
12
|
storageFailpointLayer,
|
|
12
13
|
sqlOwnerLayer,
|
|
@@ -83,8 +84,15 @@ import {
|
|
|
83
84
|
type WorkerStopCommand,
|
|
84
85
|
} from "@yielded/agent/submission-ledger";
|
|
85
86
|
import { ThreadProjectionMaintenance } from "@yielded/agent/thread-projection-maintenance";
|
|
86
|
-
import
|
|
87
|
-
|
|
87
|
+
import {
|
|
88
|
+
type ThreadReader,
|
|
89
|
+
AppendResult,
|
|
90
|
+
type AppendRequest,
|
|
91
|
+
type ThreadStoreFailure,
|
|
92
|
+
PreparedAppend,
|
|
93
|
+
ThreadStoreError,
|
|
94
|
+
ThreadStore,
|
|
95
|
+
} from "@yielded/agent/thread-store";
|
|
88
96
|
import { ToolReconciler } from "@yielded/agent/tool-reconciler";
|
|
89
97
|
import { type WakeScheduler } from "@yielded/agent/wake-scheduler";
|
|
90
98
|
import {
|
|
@@ -715,6 +723,7 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
|
|
|
715
723
|
// The RPC executor must never receive routed ports and bounce requests between Objects.
|
|
716
724
|
const rawLocalPorts = Layer.suspend(() =>
|
|
717
725
|
Layer.mergeAll(threadStoreLayer, submissionLedgerLayer).pipe(
|
|
726
|
+
Layer.provide(journalLayer),
|
|
718
727
|
Layer.provide(localInfrastructure),
|
|
719
728
|
Layer.provide(sourceProgress),
|
|
720
729
|
),
|
|
@@ -785,6 +794,54 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
|
|
|
785
794
|
// Publication remains outside this local source/index critical section.
|
|
786
795
|
const sourceCommits = yield* Semaphore.make(1);
|
|
787
796
|
|
|
797
|
+
const observeAppend = (
|
|
798
|
+
request: AppendRequest,
|
|
799
|
+
body: Effect.Effect<AppendResult, ThreadStoreFailure>,
|
|
800
|
+
) =>
|
|
801
|
+
mutations
|
|
802
|
+
.withMutation(
|
|
803
|
+
sourceCommits
|
|
804
|
+
.withPermit(
|
|
805
|
+
body.pipe(
|
|
806
|
+
Effect.tap((result) =>
|
|
807
|
+
index
|
|
808
|
+
.applyCommitted(request, result)
|
|
809
|
+
.pipe(
|
|
810
|
+
Effect.catchCause((cause) =>
|
|
811
|
+
Cause.hasInterrupts(cause)
|
|
812
|
+
? Effect.interrupt
|
|
813
|
+
: Effect.logError(
|
|
814
|
+
"Thread projection deferred after source commit",
|
|
815
|
+
cause,
|
|
816
|
+
),
|
|
817
|
+
),
|
|
818
|
+
),
|
|
819
|
+
),
|
|
820
|
+
),
|
|
821
|
+
)
|
|
822
|
+
.pipe(Effect.tap(() => afterCommit)),
|
|
823
|
+
{
|
|
824
|
+
lanes: [
|
|
825
|
+
...(options.projection === undefined ? [] : [DueQueue.Projection]),
|
|
826
|
+
...(options.lifecyclePublication === undefined ||
|
|
827
|
+
!request.batch.records.some((record) =>
|
|
828
|
+
Schema.is(Schema.toType(LifecyclePublicationFact))(record.payload),
|
|
829
|
+
)
|
|
830
|
+
? []
|
|
831
|
+
: [DueQueue.Lifecycle]),
|
|
832
|
+
],
|
|
833
|
+
},
|
|
834
|
+
)
|
|
835
|
+
.pipe(
|
|
836
|
+
Effect.catchTag("DurableAlarmError", (cause) =>
|
|
837
|
+
ThreadStoreError.make({
|
|
838
|
+
operation: "prearm publication append",
|
|
839
|
+
message: cause.message,
|
|
840
|
+
cause,
|
|
841
|
+
}),
|
|
842
|
+
),
|
|
843
|
+
);
|
|
844
|
+
|
|
788
845
|
// Every runtime-owned producer prearms too: a crash between commit and invalidation
|
|
789
846
|
// leaves a NEW, uncertified generation. Source errors keep their native port types.
|
|
790
847
|
const observedStore = ThreadStore.of({
|
|
@@ -807,52 +864,7 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
|
|
|
807
864
|
),
|
|
808
865
|
},
|
|
809
866
|
}),
|
|
810
|
-
append: (request) =>
|
|
811
|
-
mutations
|
|
812
|
-
.withMutation(
|
|
813
|
-
sourceCommits
|
|
814
|
-
.withPermit(
|
|
815
|
-
store
|
|
816
|
-
.append(request)
|
|
817
|
-
.pipe(
|
|
818
|
-
Effect.tap((result) =>
|
|
819
|
-
index
|
|
820
|
-
.applyCommitted(request, result)
|
|
821
|
-
.pipe(
|
|
822
|
-
Effect.catchCause((cause) =>
|
|
823
|
-
Cause.hasInterrupts(cause)
|
|
824
|
-
? Effect.interrupt
|
|
825
|
-
: Effect.logError(
|
|
826
|
-
"Thread projection deferred after source commit",
|
|
827
|
-
cause,
|
|
828
|
-
),
|
|
829
|
-
),
|
|
830
|
-
),
|
|
831
|
-
),
|
|
832
|
-
),
|
|
833
|
-
)
|
|
834
|
-
.pipe(Effect.tap(() => afterCommit)),
|
|
835
|
-
{
|
|
836
|
-
lanes: [
|
|
837
|
-
...(options.projection === undefined ? [] : [DueQueue.Projection]),
|
|
838
|
-
...(options.lifecyclePublication === undefined ||
|
|
839
|
-
!request.batch.records.some((record) =>
|
|
840
|
-
Schema.is(Schema.toType(LifecyclePublicationFact))(record.payload),
|
|
841
|
-
)
|
|
842
|
-
? []
|
|
843
|
-
: [DueQueue.Lifecycle]),
|
|
844
|
-
],
|
|
845
|
-
},
|
|
846
|
-
)
|
|
847
|
-
.pipe(
|
|
848
|
-
Effect.catchTag("DurableAlarmError", (cause) =>
|
|
849
|
-
ThreadStoreError.make({
|
|
850
|
-
operation: "prearm publication append",
|
|
851
|
-
message: cause.message,
|
|
852
|
-
cause,
|
|
853
|
-
}),
|
|
854
|
-
),
|
|
855
|
-
),
|
|
867
|
+
append: (request) => observeAppend(request, store.append(request)),
|
|
856
868
|
});
|
|
857
869
|
|
|
858
870
|
const observeIntent = <A, Failure>(
|
|
@@ -906,6 +918,7 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
|
|
|
906
918
|
);
|
|
907
919
|
|
|
908
920
|
const stopWorker = ledger.stopWorker;
|
|
921
|
+
const appendInput = ledger.appendInput;
|
|
909
922
|
|
|
910
923
|
return Context.make(ThreadStore, observedStore).pipe(
|
|
911
924
|
Context.add(StorageOwner, storageOwner),
|
|
@@ -967,6 +980,14 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
|
|
|
967
980
|
}),
|
|
968
981
|
Context.add(SubmissionLedger, {
|
|
969
982
|
...ledger,
|
|
983
|
+
...(appendInput === undefined
|
|
984
|
+
? {}
|
|
985
|
+
: {
|
|
986
|
+
appendInput: (submissionId, input) =>
|
|
987
|
+
Effect.flatMap(PreparedAppend.capture(input), (request) =>
|
|
988
|
+
observeAppend(request, appendInput(submissionId, request)),
|
|
989
|
+
),
|
|
990
|
+
}),
|
|
970
991
|
...(options.hostLanesForMutation === undefined &&
|
|
971
992
|
options.lifecyclePublication === undefined
|
|
972
993
|
? {}
|