mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 21:49:18 +01:00
fix(server): release settled Discord work during drain
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
7d89e7691f
commit
954a0faa75
3 files changed
+20
-2
No files matched your search
@@ -29,3 +29,17 @@ Discord command registration and receiver discovery require the same causal
|
|||||||
check at their own parents, then propagation through every dependent stack PR.
|
check at their own parents, then propagation through every dependent stack PR.
|
||||||
The full original recurring-work inventory, milestone producer audit, older E2E
|
The full original recurring-work inventory, milestone producer audit, older E2E
|
||||||
failure and inbound cleanup/deletion policy finding remain outstanding.
|
failure and inbound cleanup/deletion policy finding remain outstanding.
|
||||||
|
|
||||||
|
## Discord command registration — slice 19 / #17557
|
||||||
|
|
||||||
|
The strengthened outer-rollback/drain case reproduces active=1 after commit in
|
||||||
|
/tmp/sleep19-drain-before.log. The repair preserves the dirty scope and saved
|
||||||
|
deadlines, but reports pending dirty work only while dispatch is allowed. The
|
||||||
|
shared coordinator still holds unresolved transactions independently.
|
||||||
|
|
||||||
|
All 67 registration/store cases pass in /tmp/sleep19-drain-tests.log, including
|
||||||
|
90 seconds of no SQL/provider calls and an unchanged idle snapshot during drain,
|
||||||
|
followed by registration on resume without another producer. Production server
|
||||||
|
typecheck passes in /tmp/sleep19-drain-typecheck.log. These tests use the migrated
|
||||||
|
paperclip_sleep19_drain_20261025_test database. Remote CI/review must run on the
|
||||||
|
new head; this is not evidence of provider suspension.
|
||||||
@@ -88,7 +88,9 @@ export function registerDiscordCommandWork(
|
|||||||
if (due.length > batch.entries.length) earliest = Date.now() + 1_000;
|
if (due.length > batch.entries.length) earliest = Date.now() + 1_000;
|
||||||
if (errors.length) throw new AggregateError(errors, "Discord command registration could not settle");
|
if (errors.length) throw new AggregateError(errors, "Discord command registration could not settle");
|
||||||
},
|
},
|
||||||
hasPending: async () => dirty.size > 0,
|
// Preserve hints/deadlines for resume without holding settled intent during drain.
|
||||||
|
// The coordinator independently fences unresolved database transactions.
|
||||||
|
hasPending: async () => canRun() && dirty.size > 0,
|
||||||
nextRunAt: next,
|
nextRunAt: next,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -765,7 +765,9 @@ suite("Discord command ownership store (real PostgreSQL, no network)", () => {
|
|||||||
await sqlQuiet(60_000);
|
await sqlQuiet(60_000);
|
||||||
draining = true;
|
draining = true;
|
||||||
await db.transaction(async tx => activate(tx as unknown as typeof db));
|
await db.transaction(async tx => activate(tx as unknown as typeof db));
|
||||||
await sqlQuiet(90_000); expect(f.calls).toEqual([]);
|
await vi.waitFor(async () => { await vi.advanceTimersByTimeAsync(1000); expect(idleWorkSnapshot().active).toBe(0); });
|
||||||
|
const drained = idleWorkSnapshot();
|
||||||
|
await sqlQuiet(90_000); expect(idleWorkSnapshot()).toEqual(drained); expect(f.calls).toEqual([]);
|
||||||
draining = false;
|
draining = false;
|
||||||
await vi.advanceTimersByTimeAsync(30_000);
|
await vi.advanceTimersByTimeAsync(30_000);
|
||||||
await vi.waitFor(() => expect(f.calls).toEqual(["GET", "POST"]));
|
await vi.waitFor(() => expect(f.calls).toEqual(["GET", "POST"]));
|
||||||
|
|||||||
Reference in new issue
Block a user