From 9226871eb48cf96db71e1ae7de2343dc036e17e5 Mon Sep 17 00:00:00 2001 From: NW Date: Sat, 8 Aug 2026 11:51:18 +0100 Subject: [PATCH] =?UTF-8?q?fix(bot):=20lead=20race=20condition=20=E2=80=94?= =?UTF-8?q?=20INSERT=20OR=20IGNORE=20+=20reselect=20on=20UNIQUE=20conflict?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - getOrCreateLead: INSERT OR IGNORE prevents UNIQUE constraint race (parallel messages creating same telegram_id lead) - On changes=0, reselect existing lead instead of failing --- src/services/leadService.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/services/leadService.js b/src/services/leadService.js index 4f63896..5beee6b 100644 --- a/src/services/leadService.js +++ b/src/services/leadService.js @@ -47,7 +47,7 @@ export async function getOrCreateLead({ telegramId, username, name }) { } const result = await db.runAsync( - `INSERT INTO leads (telegram_id, telegram, name, status, verification, custom_fields, created_at, updated_at) + `INSERT OR IGNORE INTO leads (telegram_id, telegram, name, status, verification, custom_fields, created_at, updated_at) VALUES (?, ?, ?, 'new', 'pending', '{}', datetime('now'), datetime('now'))`, [ tid, @@ -55,6 +55,13 @@ export async function getOrCreateLead({ telegramId, username, name }) { name || null, ] ); + if (result.changes === 0) { + // Конфликт: лид создан параллельным запросом — перечитываем + const row = await db.getAsync('SELECT id FROM leads WHERE telegram_id = ?', [tid]); + if (row) { + return { id: row.id, isNew: false }; + } + } logger.info({ telegramId: tid, leadId: result.lastInsertRowid }, 'Lead created from bot interaction'); return { id: Number(result.lastInsertRowid), isNew: true }; } catch (err) {