fix(autogen): pg_advisory_lock + catch-up + double-check after lock

Race condition (дубли статей) устранён окончательно:

1. pg_advisory_lock по ключу категории в начале runAutogenForCategory —
   если два процесса запускаются одновременно, второй ждёт первого.
   pg_advisory_unlock в finally — освобождается всегда, даже при ошибке.

2. После получения lock — повторная проверка 'уже генерировали сегодня'
   (SELECT articles WHERE category AND created_at >= CURRENT_DATE).
   Если да — skip без генерации. Это защита от случая когда первый процесс
   завершился пока второй ждал lock.

3. draftAutoApprove catch-up при старте: если engine стартовал после 07:00
   и есть непрогнанные вчерашние черновики — одобряет их сразу.
   Раньше deploy в 07:27 приводил к тому что черновики зависали навсегда.
This commit is contained in:
Aleksei Pavlov
2026-06-21 21:30:06 +03:00
parent 630287f02f
commit 1ced06fa2d
2 changed files with 40 additions and 0 deletions
+21
View File
@@ -113,6 +113,27 @@ async function runDraftAutoApprove() {
function startDraftAutoApproveScheduler() {
console.log('[DraftApprove] scheduler started (auto-approve at 07:00 MSK, только вчерашние черновики)');
// Catch-up при старте: если сейчас уже после AUTO_APPROVE_HOUR_MSK —
// проверить есть ли вчерашние черновики которые пропустили тик.
(async () => {
const nowMsk = new Date(Date.now() + 3 * 60 * 60 * 1000);
const hourMsk = nowMsk.getUTCHours();
if (hourMsk >= AUTO_APPROVE_HOUR_MSK) {
try {
const { rows: missed } = await query(`
SELECT COUNT(*) AS cnt FROM articles
WHERE status='draft'
AND created_at AT TIME ZONE 'Europe/Moscow' >= (CURRENT_DATE - INTERVAL '1 day')::date
AND created_at AT TIME ZONE 'Europe/Moscow' < CURRENT_DATE::date
`);
if (parseInt(missed[0]?.cnt, 10) > 0) {
console.log('[DraftApprove] catch-up при старте: найдены пропущенные вчерашние черновики (' + missed[0].cnt + ' шт)');
await runAutoApprove();
}
} catch (err) { console.error('[DraftApprove] catch-up error:', err.message); }
}
})();
setInterval(() => {
const now = new Date();
const msk = new Date(now.getTime() + 3 * 60 * 60 * 1000);