feat(automations): ctx.tasks.scheduleStatusChange — отложенная смена статуса (воркер 5с, отмена при ручном переходе)

This commit is contained in:
2026-09-17 16:38:56 +03:00
parent c1fe1c4e02
commit e4f9a1992a
9 changed files with 236 additions and 1 deletions

View File

@@ -32,8 +32,9 @@ const ALLOWED_STORAGE_METHODS = new Set([
'updateUser',
'setUserProfileFieldValueFromAutomation',
'recalcUserFieldAverageFromAutomation',
// Не storage-метод: обрабатывается отдельно в обработчике storage-call (сервис сообщений)
// Не storage-методы: обрабатываются отдельно в обработчике storage-call
'sendTaskMessageFromAutomation',
'createDelayedStatusChangeFromAutomation',
]);
interface WorkerStorageCall {
@@ -99,6 +100,39 @@ export function runAutomationInWorker(
return;
}
// Отложенная смена статуса из автоматизации: планирует переход воркером
// delayed-status-change.worker (отменяется, если задача сменит статус раньше)
if (method === 'createDelayedStatusChangeFromAutomation') {
try {
const [taskId, orgId, targetStatusId, delayMs] = args as [number, number, number, number];
const task = await storage.getTask(Number(taskId), Number(orgId));
if (!task) throw new Error(`Задача ${taskId} не найдена`);
const statuses = await storage.getFormStatuses(task.formId, Number(orgId));
if (!statuses.some(s => s.id === Number(targetStatusId))) {
throw new Error(`Статус ${targetStatusId} не принадлежит форме ${task.formId}`);
}
const delay = Number(delayMs);
if (!Number.isFinite(delay) || delay < 0) throw new Error('delayMs должен быть неотрицательным числом');
const created = await storage.createDelayedStatusChange({
organizationId: Number(orgId),
taskId: task.id,
formId: task.formId,
expectedStatusId: task.currentStatusId,
targetStatusId: Number(targetStatusId),
runAt: new Date(Date.now() + delay),
});
if (!settled) {
try { worker.postMessage({ type: 'storage-response', callId, result: created }); } catch { /* terminated */ }
}
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
if (!settled) {
try { worker.postMessage({ type: 'storage-response', callId, error: message }); } catch { /* terminated */ }
}
}
return;
}
// Сообщение в чат задачи из автоматизации: не storage-метод,
// идём через сервис сообщений (SSE, вложения, messageType 'status_change')
if (method === 'sendTaskMessageFromAutomation') {