bulltrackers-module 1.0.202 → 1.0.203

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.
@@ -2,11 +2,11 @@
2
2
  * FILENAME: bulltrackers-module/functions/computation-system/helpers/computation_dispatcher.js
3
3
  * PURPOSE: Dispatches computation tasks to Pub/Sub for scalable execution.
4
4
  * FIXED: Instantiates PubSubUtils locally to ensure valid logger/dependencies are used.
5
+ * IMPROVED: Logging now explicitly lists the calculations being scheduled.
5
6
  */
6
7
 
7
8
  const { getExpectedDateStrings } = require('../utils/utils.js');
8
9
  const { groupByPass } = require('./orchestration_helpers.js');
9
- // Import PubSubUtils Class directly to ensure we can instantiate it
10
10
  const { PubSubUtils } = require('../../core/utils/pubsub_utils');
11
11
 
12
12
  const TOPIC_NAME = 'computation-tasks';
@@ -18,9 +18,7 @@ const TOPIC_NAME = 'computation-tasks';
18
18
  async function dispatchComputationPass(config, dependencies, computationManifest) {
19
19
  const { logger } = dependencies;
20
20
 
21
- // --- FIX: Create fresh PubSubUtils instance ---
22
- // This ensures we use the valid 'dependencies' (with logger & pubsub)
23
- // passed to this function, rather than relying on a potentially stale injection.
21
+ // Create fresh PubSubUtils instance
24
22
  const pubsubUtils = new PubSubUtils(dependencies);
25
23
 
26
24
  const passToRun = String(config.COMPUTATION_PASS_TO_RUN);
@@ -29,9 +27,19 @@ async function dispatchComputationPass(config, dependencies, computationManifest
29
27
  return logger.log('ERROR', '[Dispatcher] No pass defined (COMPUTATION_PASS_TO_RUN). Aborting.');
30
28
  }
31
29
 
32
- logger.log('INFO', `🚀 [Dispatcher] Preparing to dispatch PASS ${passToRun}...`);
30
+ // 1. Validate Pass Existence
31
+ const passes = groupByPass(computationManifest);
32
+ const calcsInThisPass = passes[passToRun] || [];
33
+
34
+ if (!calcsInThisPass.length) {
35
+ return logger.log('WARN', `[Dispatcher] No calcs for Pass ${passToRun}. Exiting.`);
36
+ }
37
+
38
+ const calcNames = calcsInThisPass.map(c => c.name).join(', ');
39
+ logger.log('INFO', `🚀 [Dispatcher] Preparing PASS ${passToRun}.`);
40
+ logger.log('INFO', `[Dispatcher] Included Calculations: [${calcNames}]`);
33
41
 
34
- // 1. Determine Date Range (Same logic as PassRunner)
42
+ // 2. Determine Date Range
35
43
  // Hardcoded earliest dates - keep synced with PassRunner for now
36
44
  const earliestDates = {
37
45
  portfolio: new Date('2025-09-25T00:00:00Z'),
@@ -45,19 +53,11 @@ async function dispatchComputationPass(config, dependencies, computationManifest
45
53
 
46
54
  const allExpectedDates = getExpectedDateStrings(passEarliestDate, endDateUTC);
47
55
 
48
- // 2. Validate Pass Existence
49
- const passes = groupByPass(computationManifest);
50
- const calcsInThisPass = passes[passToRun] || [];
51
-
52
- if (!calcsInThisPass.length) {
53
- return logger.log('WARN', `[Dispatcher] No calcs for Pass ${passToRun}. Exiting.`);
54
- }
55
-
56
- logger.log('INFO', `[Dispatcher] Found ${calcsInThisPass.length} calcs for Pass ${passToRun}. Target dates: ${allExpectedDates.length}`);
56
+ logger.log('INFO', `[Dispatcher] Dispatches checks for ${allExpectedDates.length} dates (${allExpectedDates[0]} to ${allExpectedDates[allExpectedDates.length - 1]}). Workers will validate dependencies.`);
57
57
 
58
58
  // 3. Dispatch Messages
59
59
  let dispatchedCount = 0;
60
- const BATCH_SIZE = 50; // Pub/Sub batch publishing size
60
+ const BATCH_SIZE = 50;
61
61
 
62
62
  // We can publish in parallel batches
63
63
  const chunks = [];
@@ -84,7 +84,7 @@ async function dispatchComputationPass(config, dependencies, computationManifest
84
84
  }
85
85
  }
86
86
 
87
- logger.log('INFO', `[Dispatcher] Finished dispatching. Total tasks: ${dispatchedCount}`);
87
+ logger.log('INFO', `[Dispatcher] Finished. Dispatched ${dispatchedCount} checks for Pass ${passToRun}.`);
88
88
  return { dispatched: dispatchedCount };
89
89
  }
90
90
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * FILENAME: bulltrackers-module/functions/computation-system/helpers/computation_worker.js
3
3
  * PURPOSE: Consumes computation tasks from Pub/Sub and executes them.
4
+ * FIXED: Added robust payload parsing to handle Cloud Functions Gen 2 (CloudEvents).
4
5
  */
5
6
 
6
7
  const { runDateComputation } = require('./computation_pass_runner.js');
@@ -8,15 +9,43 @@ const { groupByPass } = require('./orchestration_helpers.js');
8
9
 
9
10
  /**
10
11
  * Handles a single Pub/Sub message for a computation task.
12
+ * Supports both Gen 1 (Message) and Gen 2 (CloudEvent) formats.
11
13
  */
12
14
  async function handleComputationTask(message, config, dependencies, computationManifest) {
13
15
  const { logger } = dependencies;
14
16
 
17
+ let data;
15
18
  try {
16
- const data = message.json || message; // Handle both raw payload and parsed JSON
19
+ // 1. Handle Cloud Functions Gen 2 (CloudEvent)
20
+ // Structure: event.data.message.data (base64)
21
+ if (message.data && message.data.message && message.data.message.data) {
22
+ const buffer = Buffer.from(message.data.message.data, 'base64');
23
+ data = JSON.parse(buffer.toString());
24
+ }
25
+ // 2. Handle Cloud Functions Gen 1 / Legacy PubSub
26
+ // Structure: message.data (base64) or message.json
27
+ else if (message.data && typeof message.data === 'string') {
28
+ const buffer = Buffer.from(message.data, 'base64');
29
+ data = JSON.parse(buffer.toString());
30
+ }
31
+ // 3. Handle Direct JSON (Test harness or simulator)
32
+ else if (message.json) {
33
+ data = message.json;
34
+ }
35
+ // 4. Fallback: Assume message is the payload
36
+ else {
37
+ data = message;
38
+ }
39
+ } catch (parseError) {
40
+ logger.log('ERROR', `[Worker] Failed to parse Pub/Sub payload.`, { error: parseError.message });
41
+ return;
42
+ }
17
43
 
18
- if (data.action !== 'RUN_COMPUTATION_DATE') {
19
- logger.log('WARN', `[Worker] Unknown action: ${data.action}. Ignoring.`);
44
+ try {
45
+ // Validate Action
46
+ if (!data || data.action !== 'RUN_COMPUTATION_DATE') {
47
+ // Only log if data exists but action is wrong, prevents log spam on empty messages
48
+ if (data) logger.log('WARN', `[Worker] Unknown or missing action: ${data?.action}. Ignoring.`);
20
49
  return;
21
50
  }
22
51
 
@@ -39,12 +68,13 @@ async function handleComputationTask(message, config, dependencies, computationM
39
68
  }
40
69
 
41
70
  // Execute the computation for this specific date
71
+ // The runner internally checks dependencies (Pass 1, 2, 3 status) and skips if not ready.
42
72
  const result = await runDateComputation(date, pass, calcsInThisPass, config, dependencies, computationManifest);
43
73
 
44
74
  if (result) {
45
75
  logger.log('INFO', `[Worker] Successfully processed ${date} (Pass ${pass}). Updates: ${Object.keys(result.updates || {}).length}`);
46
76
  } else {
47
- logger.log('INFO', `[Worker] Processed ${date} (Pass ${pass}) - No action needed or data missing.`);
77
+ logger.log('INFO', `[Worker] Processed ${date} (Pass ${pass}) - Skipped (Dependencies missing or already done).`);
48
78
  }
49
79
 
50
80
  } catch (err) {
@@ -53,4 +83,4 @@ async function handleComputationTask(message, config, dependencies, computationM
53
83
  }
54
84
  }
55
85
 
56
- module.exports = { handleComputationTask };
86
+ module.exports = { handleComputationTask };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.202",
3
+ "version": "1.0.203",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [