fix: keep resetStuckProcessingRows private, restore test wrapper
The test wrapper forwards the in-memory outDb as the writable handle, avoiding the filesystem reopen that fails in CI. The function stays private — the optional writableOutDb param is an internal detail, not a public API. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,12 @@ import Database from 'better-sqlite3';
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import { deleteOrphanProcessingClaims, getProcessingClaims } from './db/session-db.js';
|
import { deleteOrphanProcessingClaims, getProcessingClaims } from './db/session-db.js';
|
||||||
import { ABSOLUTE_CEILING_MS, CLAIM_STUCK_MS, resetStuckProcessingRows, decideStuckAction } from './host-sweep.js';
|
import {
|
||||||
|
ABSOLUTE_CEILING_MS,
|
||||||
|
CLAIM_STUCK_MS,
|
||||||
|
_resetStuckProcessingRowsForTesting,
|
||||||
|
decideStuckAction,
|
||||||
|
} from './host-sweep.js';
|
||||||
import type { Session } from './types.js';
|
import type { Session } from './types.js';
|
||||||
|
|
||||||
const BASE = Date.parse('2026-04-20T12:00:00.000Z');
|
const BASE = Date.parse('2026-04-20T12:00:00.000Z');
|
||||||
@@ -248,7 +253,7 @@ describe('resetStuckProcessingRows — orphan claim cleanup', () => {
|
|||||||
// Sanity: the orphan claim is what would trip claim-stuck.
|
// Sanity: the orphan claim is what would trip claim-stuck.
|
||||||
expect(getProcessingClaims(outDb)).toHaveLength(1);
|
expect(getProcessingClaims(outDb)).toHaveLength(1);
|
||||||
|
|
||||||
resetStuckProcessingRows(inDb, outDb, fakeSession(), 'absolute-ceiling', outDb);
|
_resetStuckProcessingRowsForTesting(inDb, outDb, fakeSession(), 'absolute-ceiling');
|
||||||
|
|
||||||
// Regression assertion: orphan claim is gone — next sweep tick will see
|
// Regression assertion: orphan claim is gone — next sweep tick will see
|
||||||
// an empty claims list and not kill the freshly respawned container.
|
// an empty claims list and not kill the freshly respawned container.
|
||||||
@@ -280,7 +285,7 @@ describe('resetStuckProcessingRows — orphan claim cleanup', () => {
|
|||||||
.run(claimedAt, future);
|
.run(claimedAt, future);
|
||||||
outDb.prepare("INSERT INTO processing_ack VALUES ('m-2', 'processing', ?)").run(claimedAt);
|
outDb.prepare("INSERT INTO processing_ack VALUES ('m-2', 'processing', ?)").run(claimedAt);
|
||||||
|
|
||||||
resetStuckProcessingRows(inDb, outDb, fakeSession(), 'claim-stuck', outDb);
|
_resetStuckProcessingRowsForTesting(inDb, outDb, fakeSession(), 'claim-stuck');
|
||||||
|
|
||||||
expect(getProcessingClaims(outDb)).toEqual([]);
|
expect(getProcessingClaims(outDb)).toEqual([]);
|
||||||
const row = inDb.prepare('SELECT tries FROM messages_in WHERE id = ?').get('m-2') as { tries: number };
|
const row = inDb.prepare('SELECT tries FROM messages_in WHERE id = ?').get('m-2') as { tries: number };
|
||||||
|
|||||||
@@ -250,23 +250,16 @@ function enforceRunningContainerSla(
|
|||||||
resetStuckProcessingRows(inDb, outDb, session, 'claim-stuck');
|
resetStuckProcessingRows(inDb, outDb, session, 'claim-stuck');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export function _resetStuckProcessingRowsForTesting(
|
||||||
* Reset retries on inbound rows the container claimed but never acked, and
|
inDb: Database.Database,
|
||||||
* delete the orphan `processing_ack` rows so the next sweep tick doesn't
|
outDb: Database.Database,
|
||||||
* see them.
|
session: Session,
|
||||||
*
|
reason: string,
|
||||||
* Safe to call only when the container that owned `outbound.db` is dead —
|
): void {
|
||||||
* production callers invoke this either in the `!alive` branch or right
|
resetStuckProcessingRows(inDb, outDb, session, reason, outDb);
|
||||||
* after `killContainer`. Without that guarantee, the orphan-claim delete
|
}
|
||||||
* would race the container's own writer.
|
|
||||||
*
|
function resetStuckProcessingRows(
|
||||||
* `writableOutDb` is the same handle outbound writes go through. When
|
|
||||||
* omitted (typical production path) the function reopens `outbound.db`
|
|
||||||
* read-write by session path for the delete and closes that handle on
|
|
||||||
* exit. Callers that already hold a writable handle — including tests
|
|
||||||
* using in-memory DBs — can pass it in to skip the reopen.
|
|
||||||
*/
|
|
||||||
export function resetStuckProcessingRows(
|
|
||||||
inDb: Database.Database,
|
inDb: Database.Database,
|
||||||
outDb: Database.Database,
|
outDb: Database.Database,
|
||||||
session: Session,
|
session: Session,
|
||||||
|
|||||||
Reference in New Issue
Block a user