Files
buzz-sheet/scripts/outbox-worker.ts
gunshiz bdce288951
CI / Verify (push) Successful in 1m47s
CI / Build immutable images and deploy (push) Successful in 2m51s
feat
2026-10-01 22:53:48 +07:00

76 lines
2.0 KiB
TypeScript

import { closeDb } from "@/db/client";
import {
claimOutboxEvents,
markOutboxProcessed,
releaseOutboxEvent,
} from "@/lib/outbox/repository";
import {
createRedisOutboxTransport,
processOutboxEvent,
} from "@/lib/outbox/processor";
import { closeRedisClient, getRedisClient } from "@/lib/redis/client";
import { removeExpiredUnpaidCheckouts } from "@/lib/commission/cleanup";
let stopping = false;
const stop = () => {
stopping = true;
};
process.once("SIGINT", stop);
process.once("SIGTERM", stop);
function wait(milliseconds: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
function positiveInteger(
name: string,
fallback: number,
maximum: number,
): number {
const parsed = Number(process.env[name]);
return Number.isSafeInteger(parsed) && parsed > 0
? Math.min(parsed, maximum)
: fallback;
}
async function run(): Promise<void> {
const redis = await getRedisClient();
const transport = createRedisOutboxTransport(redis);
const batchSize = positiveInteger("OUTBOX_BATCH_SIZE", 20, 100);
const pollMs = positiveInteger("OUTBOX_POLL_MS", 1_000, 60_000);
const leaseMs = positiveInteger("OUTBOX_LEASE_MS", 30_000, 300_000);
let nextCheckoutCleanup = 0;
while (!stopping) {
if (Date.now() >= nextCheckoutCleanup) {
nextCheckoutCleanup = Date.now() + 60_000;
try {
await removeExpiredUnpaidCheckouts();
} catch (cause) {
console.error("Unable to remove expired unpaid checkouts", cause);
}
}
const events = await claimOutboxEvents(batchSize, leaseMs);
if (events.length === 0) {
await wait(pollMs);
continue;
}
await Promise.all(
events.map(async (event) => {
try {
await processOutboxEvent(event, transport);
await markOutboxProcessed(event.id);
} catch (cause) {
await releaseOutboxEvent(event.id, event.attempts, cause);
}
}),
);
}
}
try {
await run();
} finally {
await Promise.all([closeDb(), closeRedisClient()]);
}