bulltrackers-module 1.0.652 → 1.0.654

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.
@@ -230,23 +230,92 @@ async function handleForceRun(config, dependencies, computationManifest, reqBody
230
230
  }
231
231
 
232
232
  // 2. Determine Target Dates
233
- let targetDates = [];
233
+ let candidateDates = [];
234
234
  if (dateInput) {
235
235
  // Single Date Mode
236
- targetDates = [dateInput];
236
+ candidateDates = [dateInput];
237
237
  } else {
238
238
  // All Dates Mode (Backfill)
239
239
  logger.log('INFO', `[ForceRun] No date provided. Calculating date range for ${computationName}...`);
240
240
  const earliestDates = await getEarliestDataDates(config, dependencies);
241
241
  // Calculate from system start until today
242
- targetDates = getExpectedDateStrings(earliestDates.absoluteEarliest, new Date());
242
+ candidateDates = getExpectedDateStrings(earliestDates.absoluteEarliest, new Date());
243
243
  }
244
244
 
245
- logger.log('WARN', `[ForceRun] 🚨 MANUALLY Triggering ${computationName} for ${targetDates.length} dates. Pass: ${manifestItem.pass}`);
245
+ logger.log('INFO', `[ForceRun] Checking ${candidateDates.length} candidate dates for runnability...`);
246
246
 
247
- // 3. Construct Tasks
247
+ // 3. Filter to only runnable dates using analyzeDateExecution
248
+ const manifestMap = new Map(computationManifest.map(c => [normalizeName(c.name), c]));
249
+ const calcsInPass = groupByPass(computationManifest, manifestItem.pass || "1");
250
+ const targetComputationNormalized = normalizeName(computationName);
251
+
252
+ // Filter to only the target computation
253
+ const targetCalcs = calcsInPass.filter(c => normalizeName(c.name) === targetComputationNormalized);
254
+
255
+ if (targetCalcs.length === 0) {
256
+ throw new Error(`Computation '${computationName}' not found in pass ${manifestItem.pass || "1"}`);
257
+ }
258
+
259
+ const runnableDates = [];
260
+ const skippedDates = [];
261
+
262
+ for (const dateStr of candidateDates) {
263
+ // Check root data availability
264
+ const rootDataStatus = await checkRootDataAvailability(dateStr, config, dependencies, DEFINITIVE_EARLIEST_DATES);
265
+
266
+ // Get computation status for this date
267
+ const dailyStatus = await fetchComputationStatus(dateStr, config, dependencies);
268
+
269
+ // Check previous day status if needed
270
+ let prevDailyStatus = null;
271
+ if (targetCalcs.some(c => c.isHistorical)) {
272
+ const prevDate = new Date(dateStr + 'T00:00:00Z');
273
+ prevDate.setUTCDate(prevDate.getUTCDate() - 1);
274
+ prevDailyStatus = await fetchComputationStatus(prevDate.toISOString().slice(0, 10), config, dependencies);
275
+ }
276
+
277
+ // Analyze if this computation can run on this date
278
+ const report = analyzeDateExecution(dateStr, targetCalcs, rootDataStatus, dailyStatus, manifestMap, prevDailyStatus);
279
+
280
+ // Check if the target computation is runnable, needs re-run, or has failed dependencies
281
+ const isRunnable = report.runnable.some(t => normalizeName(t.name) === targetComputationNormalized);
282
+ const needsReRun = report.reRuns.some(t => normalizeName(t.name) === targetComputationNormalized);
283
+ const hasFailedDep = report.failedDependency.some(t => normalizeName(t.name) === targetComputationNormalized);
284
+ const isImpossible = report.impossible.some(t => normalizeName(t.name) === targetComputationNormalized);
285
+ const isBlocked = report.blocked.some(t => normalizeName(t.name) === targetComputationNormalized);
286
+
287
+ if (isRunnable || needsReRun || hasFailedDep) {
288
+ runnableDates.push(dateStr);
289
+ } else if (isImpossible) {
290
+ skippedDates.push({ date: dateStr, reason: report.impossible.find(t => normalizeName(t.name) === targetComputationNormalized)?.reason || 'Impossible' });
291
+ } else if (isBlocked) {
292
+ skippedDates.push({ date: dateStr, reason: report.blocked.find(t => normalizeName(t.name) === targetComputationNormalized)?.reason || 'Blocked' });
293
+ } else {
294
+ skippedDates.push({ date: dateStr, reason: 'Not runnable (unknown reason)' });
295
+ }
296
+ }
297
+
298
+ logger.log('INFO', `[ForceRun] ✅ Found ${runnableDates.length} runnable dates out of ${candidateDates.length} candidates`);
299
+ if (skippedDates.length > 0) {
300
+ logger.log('INFO', `[ForceRun] ⏭️ Skipped ${skippedDates.length} dates: ${skippedDates.slice(0, 5).map(s => `${s.date} (${s.reason})`).join(', ')}${skippedDates.length > 5 ? '...' : ''}`);
301
+ }
302
+
303
+ if (runnableDates.length === 0) {
304
+ return {
305
+ status: 'NO_RUNNABLE_DATES',
306
+ computation: computationName,
307
+ mode: dateInput ? 'SINGLE_DATE' : 'ALL_DATES',
308
+ datesChecked: candidateDates.length,
309
+ datesRunnable: 0,
310
+ skippedReasons: skippedDates.slice(0, 10)
311
+ };
312
+ }
313
+
314
+ logger.log('WARN', `[ForceRun] 🚨 MANUALLY Triggering ${computationName} for ${runnableDates.length} runnable dates. Pass: ${manifestItem.pass}`);
315
+
316
+ // 4. Construct Tasks (only for runnable dates)
248
317
  const dispatchId = crypto.randomUUID();
249
- const tasks = targetDates.map(date => {
318
+ const tasks = runnableDates.map(date => {
250
319
  const traceId = crypto.randomBytes(16).toString('hex');
251
320
  const spanId = crypto.randomBytes(8).toString('hex');
252
321
  return {
@@ -288,7 +357,10 @@ async function handleForceRun(config, dependencies, computationManifest, reqBody
288
357
  status: 'FORCED',
289
358
  computation: computationName,
290
359
  mode: dateInput ? 'SINGLE_DATE' : 'ALL_DATES',
360
+ datesChecked: candidateDates.length,
361
+ datesRunnable: runnableDates.length,
291
362
  datesTriggered: dispatchedCount,
363
+ skippedCount: skippedDates.length,
292
364
  targetTopic: topic
293
365
  };
294
366
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.652",
3
+ "version": "1.0.654",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [