mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(minions): unify JSONB inserts, tighten nullish coalescing
Three non-blocker cleanups from post-ship review of v0.11.0: - queue.ts add() and completeJob(): pre-stringifying with JSON.stringify while other sites pass raw objects with $n::jsonb casts. postgres.js double-encodes if you stringify first — works on PGLite (text→JSONB auto-cast), fails silently on real PG. Unify on raw object + explicit $n::jsonb cast. - queue.ts readChildCompletions: since clause used sent_at > $2 relying on PG's implicit text→TIMESTAMPTZ coercion. Explicit $2::timestamptz is safer and clearer. - types.ts rowToMinionJob: parent_job_id used || which coerces 0 to null. Harmless today (SERIAL IDs start at 1) but ?? is semantically correct. All 110 unit tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
5382ee0309
commit
c502b7ea6d
@@ -113,13 +113,13 @@ export class MinionQueue {
|
|||||||
? `INSERT INTO minion_jobs (name, queue, status, priority, data, max_attempts, backoff_type,
|
? `INSERT INTO minion_jobs (name, queue, status, priority, data, max_attempts, backoff_type,
|
||||||
backoff_delay, backoff_jitter, delay_until, parent_job_id, on_child_fail,
|
backoff_delay, backoff_jitter, delay_until, parent_job_id, on_child_fail,
|
||||||
depth, max_children, timeout_ms, remove_on_complete, remove_on_fail, idempotency_key)
|
depth, max_children, timeout_ms, remove_on_complete, remove_on_fail, idempotency_key)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
VALUES ($1, $2, $3, $4, $5::jsonb, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||||
ON CONFLICT (idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING
|
ON CONFLICT (idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING
|
||||||
RETURNING *`
|
RETURNING *`
|
||||||
: `INSERT INTO minion_jobs (name, queue, status, priority, data, max_attempts, backoff_type,
|
: `INSERT INTO minion_jobs (name, queue, status, priority, data, max_attempts, backoff_type,
|
||||||
backoff_delay, backoff_jitter, delay_until, parent_job_id, on_child_fail,
|
backoff_delay, backoff_jitter, delay_until, parent_job_id, on_child_fail,
|
||||||
depth, max_children, timeout_ms, remove_on_complete, remove_on_fail, idempotency_key)
|
depth, max_children, timeout_ms, remove_on_complete, remove_on_fail, idempotency_key)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
VALUES ($1, $2, $3, $4, $5::jsonb, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||||
RETURNING *`;
|
RETURNING *`;
|
||||||
|
|
||||||
const params = [
|
const params = [
|
||||||
@@ -127,7 +127,7 @@ export class MinionQueue {
|
|||||||
opts?.queue ?? 'default',
|
opts?.queue ?? 'default',
|
||||||
childStatus,
|
childStatus,
|
||||||
opts?.priority ?? 0,
|
opts?.priority ?? 0,
|
||||||
JSON.stringify(data ?? {}),
|
data ?? {},
|
||||||
opts?.max_attempts ?? 3,
|
opts?.max_attempts ?? 3,
|
||||||
opts?.backoff_type ?? 'exponential',
|
opts?.backoff_type ?? 'exponential',
|
||||||
opts?.backoff_delay ?? 1000,
|
opts?.backoff_delay ?? 1000,
|
||||||
@@ -450,11 +450,11 @@ export class MinionQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rows = await tx.executeRaw<Record<string, unknown>>(
|
const rows = await tx.executeRaw<Record<string, unknown>>(
|
||||||
`UPDATE minion_jobs SET status = 'completed', result = $1,
|
`UPDATE minion_jobs SET status = 'completed', result = $1::jsonb,
|
||||||
finished_at = now(), lock_token = NULL, lock_until = NULL, updated_at = now()
|
finished_at = now(), lock_token = NULL, lock_until = NULL, updated_at = now()
|
||||||
WHERE id = $2 AND status = 'active' AND lock_token = $3
|
WHERE id = $2 AND status = 'active' AND lock_token = $3
|
||||||
RETURNING *`,
|
RETURNING *`,
|
||||||
[result ? JSON.stringify(result) : null, id, lockToken]
|
[result ?? null, id, lockToken]
|
||||||
);
|
);
|
||||||
if (rows.length === 0) return null;
|
if (rows.length === 0) return null;
|
||||||
|
|
||||||
@@ -841,7 +841,7 @@ export class MinionQueue {
|
|||||||
const params: unknown[] = [parentId];
|
const params: unknown[] = [parentId];
|
||||||
let sinceClause = '';
|
let sinceClause = '';
|
||||||
if (opts?.since) {
|
if (opts?.since) {
|
||||||
sinceClause = ` AND sent_at > $2`;
|
sinceClause = ` AND sent_at > $2::timestamptz`;
|
||||||
params.push(opts.since.toISOString());
|
params.push(opts.since.toISOString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ export function rowToMinionJob(row: Record<string, unknown>): MinionJob {
|
|||||||
lock_token: (row.lock_token as string) || null,
|
lock_token: (row.lock_token as string) || null,
|
||||||
lock_until: row.lock_until ? new Date(row.lock_until as string) : null,
|
lock_until: row.lock_until ? new Date(row.lock_until as string) : null,
|
||||||
delay_until: row.delay_until ? new Date(row.delay_until as string) : null,
|
delay_until: row.delay_until ? new Date(row.delay_until as string) : null,
|
||||||
parent_job_id: (row.parent_job_id as number) || null,
|
parent_job_id: (row.parent_job_id as number | null) ?? null,
|
||||||
on_child_fail: row.on_child_fail as ChildFailPolicy,
|
on_child_fail: row.on_child_fail as ChildFailPolicy,
|
||||||
tokens_input: (row.tokens_input as number) ?? 0,
|
tokens_input: (row.tokens_input as number) ?? 0,
|
||||||
tokens_output: (row.tokens_output as number) ?? 0,
|
tokens_output: (row.tokens_output as number) ?? 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user