mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-02 16:58:52 +01:00
Merge qualified recovery grouping and prerequisites
Co-Authored-By: Paperclip <noreply@paperclip.ing> * commit '2aa0179c35564fae529eb8053f0ed098f60dcc64': Preserve native receipt grouping within each bounded worker pass
This commit is contained in:
commit
0b081d9ffe
5 files changed
+197
-27
No files matched your search
@@ -4214,7 +4214,7 @@ export function heartbeatService(
|
||||
registerDeferredReceiptWork(db, coordinator, {
|
||||
resume: scope => heartbeatQueue.resumeDeferredExecutionReceipts(scope),
|
||||
settleTaskChat: scope => reconcileTaskChatRetryReceipts(db, { ...scope, settleOnly: true }),
|
||||
dispatchNative: dispatchPendingNativeStatusWakeups,
|
||||
createNativeBatch: heartbeatQueue.createNativeStatusWakeBatch,
|
||||
schedulingSuppressed: async () => (await getSchedulingSuppression(true)).suppressed,
|
||||
}, () => canRun() && readTaskDrain(new Date()) === null),
|
||||
registerIssueStateRecoveryWork: (coordinator: Parameters<typeof registerIssueRecoveryWork>[1], canRun: () => boolean) =>
|
||||
|
||||
@@ -18,7 +18,7 @@ export function registerDeferredReceiptWork(
|
||||
owner: {
|
||||
resume(scope: DeferredReceiptRecoveryOptions): Promise<unknown>;
|
||||
settleTaskChat(scope: DeferredExecutionScope): Promise<unknown>;
|
||||
dispatchNative(scope: NativeIntentOptions): Promise<unknown>;
|
||||
createNativeBatch(): (scope: NativeIntentOptions) => Promise<unknown>;
|
||||
schedulingSuppressed(): Promise<boolean>;
|
||||
},
|
||||
canRun: () => boolean,
|
||||
@@ -26,12 +26,17 @@ export function registerDeferredReceiptWork(
|
||||
function register(kind: "deferred" | "task_chat" | "native") {
|
||||
const cursors = new Map<string, string>();
|
||||
let enabled = false;
|
||||
let dispatchNative: ReturnType<typeof owner.createNativeBatch>;
|
||||
const queue = kind === "deferred" ? DELIVERY_QUEUES.deferredExecutionReceipts
|
||||
: kind === "task_chat" ? DELIVERY_QUEUES.taskRetryReceiptSettlement : DELIVERY_QUEUES.nativeStatusWakeIntents;
|
||||
return registerScopedDeadlineWork<Entry, DeferredExecutionScope>(coordinator, {
|
||||
queue,
|
||||
batchSize: kind === "native" ? 100 : undefined,
|
||||
reconstructionIntervalMs: 30_000,
|
||||
beforePass: async () => { enabled = !(await owner.schedulingSuppressed()); },
|
||||
beforePass: async () => {
|
||||
enabled = !(await owner.schedulingSuppressed());
|
||||
if (kind === "native") dispatchNative = owner.createNativeBatch();
|
||||
},
|
||||
decodeScope: hint => hint === "*" ? undefined : JSON.parse(hint),
|
||||
matches: (entry, scope) => !scope || entry.companyId === scope.companyId && (!scope.requestId || entry.id === scope.requestId),
|
||||
load: async scope => {
|
||||
@@ -101,7 +106,7 @@ export function registerDeferredReceiptWork(
|
||||
const errors: unknown[] = [];
|
||||
let next: number | null = null;
|
||||
const scope = { companyId: entry.companyId, requestId: entry.id };
|
||||
if (kind === "native") await owner.dispatchNative({ ...scope,
|
||||
if (kind === "native") await dispatchNative({ ...scope,
|
||||
onDeferredDeadline: at => { next = next === null ? at : Math.min(next, at); },
|
||||
onError: error => { errors.push(error); },
|
||||
});
|
||||
|
||||
@@ -4779,15 +4779,27 @@ export function createHeartbeatQueue(db: Db, dependencies: HeartbeatQueueDepende
|
||||
* wake was inserted but before the intent was linked to it. Dispatch failure
|
||||
* only requeues the intent; it never changes the provider run outcome.
|
||||
*/
|
||||
async function dispatchPendingNativeStatusWakeups(
|
||||
input: {
|
||||
companyId?: string;
|
||||
limit?: number;
|
||||
staleClaimMs?: number;
|
||||
requestId?: string;
|
||||
onDeferredDeadline?: (at: number) => void;
|
||||
onError?: (error: unknown) => void;
|
||||
} = {},
|
||||
type NativeStatusWakeDispatchInput = {
|
||||
companyId?: string;
|
||||
limit?: number;
|
||||
staleClaimMs?: number;
|
||||
requestId?: string;
|
||||
onDeferredDeadline?: (at: number) => void;
|
||||
onError?: (error: unknown) => void;
|
||||
};
|
||||
type NativeStatusWakeDelivery = { runId: string | null; status: string };
|
||||
|
||||
function createNativeStatusWakeBatch() {
|
||||
const deliveredByIssueScope = new Map<string, NativeStatusWakeDelivery>();
|
||||
return (input: NativeStatusWakeDispatchInput = {}) => dispatchNativeStatusWakeBatch(input, deliveredByIssueScope);
|
||||
}
|
||||
|
||||
function dispatchPendingNativeStatusWakeups(input: NativeStatusWakeDispatchInput = {}) {
|
||||
return createNativeStatusWakeBatch()(input);
|
||||
}
|
||||
|
||||
async function dispatchNativeStatusWakeBatch(input: NativeStatusWakeDispatchInput,
|
||||
deliveredByIssueScope: Map<string, NativeStatusWakeDelivery>,
|
||||
) {
|
||||
const now = new Date();
|
||||
const staleClaimMs = Math.max(1_000, input.staleClaimMs ?? 60_000);
|
||||
@@ -4812,10 +4824,6 @@ export function createHeartbeatQueue(db: Db, dependencies: HeartbeatQueueDepende
|
||||
let dispatched = 0;
|
||||
let recovered = 0;
|
||||
let deferred = 0;
|
||||
const deliveredByIssueScope = new Map<
|
||||
string,
|
||||
{ runId: string | null; status: string }
|
||||
>();
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const payload = parseObject(candidate.payload);
|
||||
@@ -5088,6 +5096,7 @@ export function createHeartbeatQueue(db: Db, dependencies: HeartbeatQueueDepende
|
||||
return {
|
||||
enqueueWakeup,
|
||||
dispatchPendingNativeStatusWakeups,
|
||||
createNativeStatusWakeBatch,
|
||||
startNextQueuedRunForAgent,
|
||||
countRunningRunsForAgent,
|
||||
releaseRunClaimedJustBeforeSuppression,
|
||||
|
||||
Reference in new issue
Block a user