Initial commit: OmniAI backend server
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
const billing = require("./billing");
|
||||
|
||||
const SETTLEMENT_INTERVAL_MS = 5 * 60 * 1000;
|
||||
const LEAK_THRESHOLD_MINUTES = 10;
|
||||
|
||||
let timerId = null;
|
||||
|
||||
async function settleOrphanedLeases() {
|
||||
const { pool, withTransaction } = require("./db");
|
||||
const now = new Date();
|
||||
const leakCutoff = new Date(now.getTime() - LEAK_THRESHOLD_MINUTES * 60 * 1000).toISOString();
|
||||
|
||||
const { rows: releasedUnsettled } = await pool.query(`
|
||||
SELECT id FROM key_leases
|
||||
WHERE settled = 0 AND released_at IS NOT NULL
|
||||
`);
|
||||
|
||||
const { rows: leaked } = await pool.query(
|
||||
`
|
||||
SELECT id, key_id FROM key_leases
|
||||
WHERE settled = 0 AND released_at IS NULL AND leased_at < $1
|
||||
`,
|
||||
[leakCutoff],
|
||||
);
|
||||
|
||||
if (leaked.length > 0) {
|
||||
await withTransaction(async (client) => {
|
||||
for (const lease of leaked) {
|
||||
await client.query("UPDATE key_leases SET released_at = NOW() WHERE id = $1", [lease.id]);
|
||||
await client.query(
|
||||
"UPDATE api_keys SET active_count = GREATEST(0, active_count - 1) WHERE id = $1",
|
||||
[lease.key_id],
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const allOrphaned = [...releasedUnsettled, ...leaked];
|
||||
let settled = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const lease of allOrphaned) {
|
||||
try {
|
||||
await billing.forceSettleLease(lease.id);
|
||||
settled++;
|
||||
} catch (err) {
|
||||
console.error("[settlementWorker] failed to settle lease", lease.id, err.message);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (settled > 0 || failed > 0) {
|
||||
console.log(
|
||||
`[settlementWorker] settled=${settled} failed=${failed} released_unsettled=${releasedUnsettled.length} leaked=${leaked.length}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function startSettlementWorker() {
|
||||
if (timerId) return;
|
||||
|
||||
settleOrphanedLeases().catch((err) => {
|
||||
console.error("[settlementWorker] initial run failed", err.message);
|
||||
});
|
||||
|
||||
timerId = setInterval(() => {
|
||||
settleOrphanedLeases().catch((err) => {
|
||||
console.error("[settlementWorker] periodic run failed", err.message);
|
||||
});
|
||||
}, SETTLEMENT_INTERVAL_MS);
|
||||
|
||||
if (timerId.unref) {
|
||||
timerId.unref();
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[settlementWorker] started (interval=${SETTLEMENT_INTERVAL_MS}ms, leakThreshold=${LEAK_THRESHOLD_MINUTES}min)`,
|
||||
);
|
||||
}
|
||||
|
||||
function stopSettlementWorker() {
|
||||
if (timerId) {
|
||||
clearInterval(timerId);
|
||||
timerId = null;
|
||||
console.log("[settlementWorker] stopped");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { startSettlementWorker, stopSettlementWorker, settleOrphanedLeases };
|
||||
Reference in New Issue
Block a user