bulltrackers-module 1.0.272 → 1.0.274
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FILENAME: computation-system/helpers/computation_worker.js
|
|
3
3
|
* PURPOSE: Consumes computation tasks from Pub/Sub and executes them.
|
|
4
|
+
* UPDATED: Added Deterministic Error Short-Circuit to prevent infinite retry storms on data limits.
|
|
4
5
|
* UPDATED: Integrated Run Ledger for per-run/per-date success/failure tracking.
|
|
5
|
-
* UPDATED: Added Dead Letter Queue logic for Poison Pills.
|
|
6
|
-
* UPDATED: Now logs the trigger reason.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
const { executeDispatchTask } = require('../WorkflowOrchestrator.js');
|
|
@@ -89,6 +88,35 @@ async function handleComputationTask(message, config, dependencies) {
|
|
|
89
88
|
await recordRunAttempt(db, { date, computation, pass }, 'SUCCESS', { message: 'Empty Result' }, { durationMs: duration }, triggerReason);
|
|
90
89
|
}
|
|
91
90
|
} catch (err) {
|
|
91
|
+
// ----------------------------------- ERROR HANDLING & RETRY LOGIC -----------------------------------
|
|
92
|
+
|
|
93
|
+
// 1. DETERMINISTIC ERROR CHECK (Short-Circuit)
|
|
94
|
+
// If the error is permanent (like "Too Big" or "Validation Failed"), DO NOT RETRY.
|
|
95
|
+
// This stops the "Retry Storm" where we pay for 3-4 retries of a task that will never succeed.
|
|
96
|
+
const isDeterministicError = err.stage === 'SHARDING_LIMIT_EXCEEDED' ||
|
|
97
|
+
err.stage === 'QUALITY_CIRCUIT_BREAKER' ||
|
|
98
|
+
(err.message && (err.message.includes('INVALID_ARGUMENT') || err.message.includes('Transaction too big')));
|
|
99
|
+
|
|
100
|
+
if (isDeterministicError) {
|
|
101
|
+
logger.log('ERROR', `[Worker] 🛑 Permanent Failure (Data/Limit Issue). Sending to DLQ immediately: ${computation} ${date}`);
|
|
102
|
+
try {
|
|
103
|
+
await db.collection('computation_dead_letter_queue').add({
|
|
104
|
+
originalData: data,
|
|
105
|
+
error: { message: err.message, stack: err.stack, stage: err.stage || 'UNKNOWN' },
|
|
106
|
+
finalAttemptAt: new Date(),
|
|
107
|
+
failureReason: 'PERMANENT_DETERMINISTIC_ERROR'
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// CRITICAL: We record the failure but return successfully to Pub/Sub to ACK the message and stop retries.
|
|
111
|
+
// This ensures the task is marked as Failed in run history, but does NOT block the queue.
|
|
112
|
+
await recordRunAttempt(db, { date, computation, pass }, 'FAILURE', { message: err.message, stage: err.stage || 'PERMANENT_FAIL' }, { durationMs: 0 }, triggerReason);
|
|
113
|
+
return;
|
|
114
|
+
} catch (dlqErr) {
|
|
115
|
+
logger.log('FATAL', `[Worker] Failed to write to DLQ for deterministic error`, dlqErr);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 2. STANDARD RETRY LOGIC (Timeout / Crash)
|
|
92
120
|
const retryCount = message.deliveryAttempt || 0;
|
|
93
121
|
if (retryCount >= MAX_RETRIES) {
|
|
94
122
|
logger.log('ERROR', `[Worker] ☠️ Task POISONED. Moved to DLQ: ${computation} ${date} (Attempt ${retryCount})`);
|
|
@@ -102,6 +130,8 @@ async function handleComputationTask(message, config, dependencies) {
|
|
|
102
130
|
return;
|
|
103
131
|
} catch (dlqErr) { logger.log('FATAL', `[Worker] Failed to write to DLQ`, dlqErr); }
|
|
104
132
|
}
|
|
133
|
+
|
|
134
|
+
// If it's not deterministic and not max retries, we throw to let Pub/Sub retry it.
|
|
105
135
|
logger.log('ERROR', `[Worker] ❌ Crash: ${computation} for ${date}: ${err.message}`);
|
|
106
136
|
await recordRunAttempt(db, { date, computation, pass }, 'CRASH', { message: err.message, stack: err.stack, stage: 'SYSTEM_CRASH' }, { durationMs: 0 }, triggerReason);
|
|
107
137
|
throw err;
|