bulltrackers-module 1.0.743 → 1.0.745

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.
@@ -43,6 +43,35 @@ class StorageManager {
43
43
  }
44
44
  return this._firestore;
45
45
  }
46
+
47
+ /**
48
+ * Updates the heartbeat of a zombie to "hide" it from detection
49
+ * while the recovery task is being queued.
50
+ */
51
+ async claimZombie(checkpointId) {
52
+ if (!checkpointId) return;
53
+
54
+ // FIX: Access projectId and dataset from the config object
55
+ const { projectId, dataset } = this.config.bigquery; //
56
+
57
+ const query = `
58
+ UPDATE \`${projectId}.${dataset}.computation_checkpoints\`
59
+ SET last_updated = CURRENT_TIMESTAMP()
60
+ WHERE checkpoint_id = @checkpointId
61
+ `;
62
+
63
+ try {
64
+ await this.bigquery.query({
65
+ query,
66
+ params: { checkpointId }
67
+ });
68
+ } catch (e) {
69
+ // Ignore errors here, it's an optimization, not critical
70
+ console.warn(`[Storage] Failed to claim zombie ${checkpointId}: ${e.message}`);
71
+ }
72
+ }
73
+
74
+
46
75
 
47
76
  // =========================================================================
48
77
  // RESULT COMMITTING (Batch -> GCS Buffer)
@@ -696,6 +725,7 @@ class StorageManager {
696
725
 
697
726
  this._log('ERROR', `${context}: ${details}`);
698
727
  }
728
+
699
729
  }
700
730
 
701
731
  module.exports = { StorageManager };
@@ -10,16 +10,21 @@
10
10
  * the Scheduler and the Worker.
11
11
  */
12
12
 
13
- const system = require('../index');
13
+ // REMOVED: const system = require('../index');
14
+ // We will lazy-load this inside the handler to prevent circular dependency cycles.
14
15
 
15
16
  exports.dispatcherHandler = async (req, res) => {
16
17
  const startTime = Date.now();
17
18
 
18
19
  try {
20
+ // LAZY LOAD: Require index.js here to ensure it is fully initialized
21
+ // This fixes the "Accessing non-existent property inside circular dependency" error
22
+ const system = require('../index');
23
+
19
24
  const {
20
25
  computationName,
21
26
  targetDate,
22
- source = 'scheduled', // 'scheduled' | 'on-demand'
27
+ source = 'scheduled', // 'scheduled' | 'on-demand' | 'zombie-recovery'
23
28
  entityIds, // Optional: specific entities
24
29
  dryRun = false,
25
30
  force = false // Optional: run even if hash matches
@@ -36,6 +41,11 @@ exports.dispatcherHandler = async (req, res) => {
36
41
 
37
42
  const date = targetDate || new Date().toISOString().split('T')[0];
38
43
  console.log(`[Dispatcher] Received ${source} request: ${computationName} for ${date}`);
44
+
45
+ // Safety check to ensure system is loaded correctly
46
+ if (!system || typeof system.runComputation !== 'function') {
47
+ throw new Error('System not fully initialized (runComputation is missing). Check index.js exports.');
48
+ }
39
49
 
40
50
  // 2. DELEGATE TO ORCHESTRATOR
41
51
  // The Orchestrator calls RunAnalyzer internally to check:
@@ -74,7 +84,7 @@ exports.dispatcherHandler = async (req, res) => {
74
84
 
75
85
  // Scheduled tasks need 503 to trigger retry
76
86
  // On-demand users need 200 to see the error message immediately
77
- const httpStatus = source === 'scheduled' ? 503 : 200;
87
+ const httpStatus = source === 'scheduled' || source === 'zombie-recovery' ? 503 : 200;
78
88
 
79
89
  return res.status(httpStatus).json({
80
90
  status: result.status,
@@ -51,14 +51,21 @@ async function schedulerHandler(req, res) {
51
51
  const dueComputations = findDueComputations(now);
52
52
 
53
53
  // 2. ZOMBIE DETECTION
54
- // Find tasks marked 'running' that haven't heartbeated in X mins
55
54
  let zombies = [];
56
55
  try {
57
56
  zombies = await storageManager.findZombies(ZOMBIE_THRESHOLD_MINUTES);
58
- // New Code
57
+
59
58
  if (zombies.length > 0) {
60
59
  const zombieDetails = zombies.map(z => `${z.name} [${z.date}]`).join(', ');
61
60
  console.log(`[Scheduler] DETECTED ${zombies.length} ZOMBIES: ${zombieDetails}`);
61
+
62
+ // --- NEW FIX: CLAIM ZOMBIES ---
63
+ // "Touch" these rows in the DB so they don't look like zombies for another 15 mins.
64
+ // This prevents re-dispatching the same task 15 times if the queue is slow.
65
+ await Promise.all(zombies.map(z =>
66
+ storageManager.claimZombie(z.checkpointId)
67
+ ));
68
+ // ------------------------------
62
69
  }
63
70
  } catch (e) {
64
71
  console.error(`[Scheduler] Zombie check failed: ${e.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.743",
3
+ "version": "1.0.745",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [