bulltrackers-module 1.0.267 → 1.0.268
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,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Build Reporter & Auto-Runner.
|
|
3
3
|
* Generates a "Pre-Flight" report of what the computation system WILL do.
|
|
4
|
-
* UPDATED:
|
|
5
|
-
* UPDATED: Now reports specific reasons for Re-Runs.
|
|
4
|
+
* UPDATED: Shards report details to subcollections to bypass 1MB limit on 'Invalidate All' scenarios.
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
7
|
const { analyzeDateExecution } = require('../WorkflowOrchestrator');
|
|
9
8
|
const { fetchComputationStatus } = require('../persistence/StatusRepository');
|
|
10
9
|
const { normalizeName, getExpectedDateStrings, DEFINITIVE_EARLIEST_DATES } = require('../utils/utils');
|
|
11
10
|
const { checkRootDataAvailability } = require('../data/AvailabilityChecker');
|
|
11
|
+
const { commitBatchInChunks } = require('../persistence/FirestoreUtils'); // Reuse chunker
|
|
12
12
|
const pLimit = require('p-limit');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const packageJson = require(path.join(__dirname, '..', '..', '..', 'package.json'));
|
|
@@ -21,13 +21,11 @@ const packageVersion = pac
|
|
|
21
21
|
async function ensureBuildReport(config, dependencies, manifest) {
|
|
22
22
|
const { db, logger } = dependencies;
|
|
23
23
|
const now = new Date();
|
|
24
|
-
// Create a standardized build ID
|
|
25
24
|
const buildId = `v${packageVersion}_${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}-${String(now.getDate()).padStart(2,'0')}_${String(now.getHours()).padStart(2,'0')}-${String(now.getMinutes()).padStart(2,'0')}-${String(now.getSeconds()).padStart(2,'0')}`;
|
|
26
25
|
const latestRef = db.collection('computation_build_records').doc('latest');
|
|
27
26
|
|
|
28
27
|
try {
|
|
29
28
|
const latestDoc = await latestRef.get();
|
|
30
|
-
// Check using 'packageVersion' key to match what we store
|
|
31
29
|
const priorVersion = latestDoc.exists ? latestDoc.data().packageVersion : null;
|
|
32
30
|
|
|
33
31
|
if (priorVersion === packageVersion) {
|
|
@@ -37,7 +35,7 @@ async function ensureBuildReport(config, dependencies, manifest) {
|
|
|
37
35
|
|
|
38
36
|
logger.log('INFO', `[BuildReporter] 🚀 New Version Detected (${packageVersion}). Auto-running Pre-flight Report...`);
|
|
39
37
|
|
|
40
|
-
//
|
|
38
|
+
// Scope: 90 days is fine now that we shard the output
|
|
41
39
|
await generateBuildReport(config, dependencies, manifest, 90, buildId);
|
|
42
40
|
|
|
43
41
|
} catch (e) {
|
|
@@ -46,7 +44,7 @@ async function ensureBuildReport(config, dependencies, manifest) {
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
/**
|
|
49
|
-
* Generates the report and saves to Firestore.
|
|
47
|
+
* Generates the report and saves to Firestore (Sharded).
|
|
50
48
|
*/
|
|
51
49
|
async function generateBuildReport(config, dependencies, manifest, daysBack = 90, customBuildId = null) {
|
|
52
50
|
const { db, logger } = dependencies;
|
|
@@ -54,7 +52,6 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
54
52
|
|
|
55
53
|
logger.log('INFO', `[BuildReporter] Generating Build Report: ${buildId} (Scope: ${daysBack} days)...`);
|
|
56
54
|
|
|
57
|
-
// 1. Determine Date Range
|
|
58
55
|
const today = new Date();
|
|
59
56
|
const startDate = new Date();
|
|
60
57
|
startDate.setDate(today.getDate() - daysBack);
|
|
@@ -62,37 +59,33 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
62
59
|
const datesToCheck = getExpectedDateStrings(startDate, today);
|
|
63
60
|
const manifestMap = new Map(manifest.map(c => [normalizeName(c.name), c]));
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
// Main Report Header (Summary Only)
|
|
63
|
+
const reportHeader = {
|
|
66
64
|
buildId,
|
|
67
65
|
packageVersion: packageVersion,
|
|
68
66
|
generatedAt: new Date().toISOString(),
|
|
69
67
|
summary: {},
|
|
70
|
-
|
|
68
|
+
_sharded: true // Flag to tell UI/Tools to look in subcollection
|
|
71
69
|
};
|
|
72
70
|
|
|
73
71
|
let totalReRuns = 0;
|
|
74
72
|
let totalNew = 0;
|
|
73
|
+
const detailWrites = []; // Accumulate writes for batching
|
|
75
74
|
|
|
76
|
-
// 2. PARALLEL PROCESSING
|
|
77
75
|
const limit = pLimit(20);
|
|
78
76
|
|
|
79
77
|
const processingPromises = datesToCheck.map(dateStr => limit(async () => {
|
|
80
78
|
try {
|
|
81
|
-
// [IMPROVED] Fetch all statuses in parallel
|
|
82
79
|
const fetchPromises = [
|
|
83
|
-
// A. Real status
|
|
84
80
|
fetchComputationStatus(dateStr, config, dependencies),
|
|
85
|
-
// C. Real Root Data
|
|
86
81
|
checkRootDataAvailability(dateStr, config, dependencies, DEFINITIVE_EARLIEST_DATES)
|
|
87
82
|
];
|
|
88
83
|
|
|
89
|
-
// B. Yesterday's Status (only if needed)
|
|
90
84
|
let prevDateStr = null;
|
|
91
85
|
if (manifest.some(c => c.isHistorical)) {
|
|
92
86
|
const prevDate = new Date(dateStr + 'T00:00:00Z');
|
|
93
87
|
prevDate.setUTCDate(prevDate.getUTCDate() - 1);
|
|
94
88
|
prevDateStr = prevDate.toISOString().slice(0, 10);
|
|
95
|
-
|
|
96
89
|
if (prevDate >= DEFINITIVE_EARLIEST_DATES.absoluteEarliest) {
|
|
97
90
|
fetchPromises.push(fetchComputationStatus(prevDateStr, config, dependencies));
|
|
98
91
|
}
|
|
@@ -101,18 +94,13 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
101
94
|
const results = await Promise.all(fetchPromises);
|
|
102
95
|
const dailyStatus = results[0];
|
|
103
96
|
const availability = results[1];
|
|
104
|
-
// If we fetched prevStatus, it's at index 2
|
|
105
97
|
const prevDailyStatus = (prevDateStr && results[2]) ? results[2] : (prevDateStr ? {} : null);
|
|
106
|
-
|
|
107
98
|
const rootDataStatus = availability ? availability.status : { hasPortfolio: false, hasHistory: false, hasSocial: false, hasInsights: false, hasPrices: false };
|
|
108
99
|
|
|
109
|
-
// D. Run Logic Analysis
|
|
110
100
|
const analysis = analyzeDateExecution(dateStr, manifest, rootDataStatus, dailyStatus, manifestMap, prevDailyStatus);
|
|
111
101
|
|
|
112
|
-
// E. Format Findings
|
|
113
102
|
const dateSummary = { willRun: [], willReRun: [], blocked: [], impossible: [] };
|
|
114
103
|
|
|
115
|
-
// Pass the generated "Reason" string through to the report
|
|
116
104
|
analysis.runnable.forEach (item => dateSummary.willRun.push ({ name: item.name, reason: "New / No Previous Record" }));
|
|
117
105
|
analysis.reRuns.forEach (item => dateSummary.willReRun.push ({ name: item.name, reason: item.reason || "Hash Mismatch" }));
|
|
118
106
|
analysis.impossible.forEach (item => dateSummary.impossible.push ({ name: item.name, reason: item.reason }));
|
|
@@ -120,12 +108,19 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
120
108
|
|
|
121
109
|
const hasUpdates = dateSummary.willRun.length || dateSummary.willReRun.length || dateSummary.blocked.length || dateSummary.impossible.length;
|
|
122
110
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
if (hasUpdates) {
|
|
112
|
+
// Prepare Write for Subcollection
|
|
113
|
+
const detailRef = db.collection('computation_build_records').doc(buildId).collection('details').doc(dateStr);
|
|
114
|
+
detailWrites.push({
|
|
115
|
+
ref: detailRef,
|
|
116
|
+
data: dateSummary
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
stats: { new: dateSummary.willRun.length, rerun: dateSummary.willReRun.length }
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
129
124
|
|
|
130
125
|
} catch (err) {
|
|
131
126
|
logger.log('ERROR', `[BuildReporter] Error analyzing date ${dateStr}: ${err.message}`);
|
|
@@ -135,30 +130,34 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
135
130
|
|
|
136
131
|
const results = await Promise.all(processingPromises);
|
|
137
132
|
|
|
138
|
-
// 3. Aggregate Results
|
|
139
133
|
results.forEach(res => {
|
|
140
|
-
if (res
|
|
141
|
-
reportData.dates[res.dateStr] = res.dateSummary;
|
|
134
|
+
if (res) {
|
|
142
135
|
totalNew += res.stats.new;
|
|
143
136
|
totalReRuns += res.stats.rerun;
|
|
144
137
|
}
|
|
145
138
|
});
|
|
146
139
|
|
|
147
|
-
|
|
140
|
+
reportHeader.summary = { totalReRuns, totalNew, scanRange: `${datesToCheck[0]} to ${datesToCheck[datesToCheck.length-1]}` };
|
|
148
141
|
|
|
149
|
-
//
|
|
142
|
+
// 1. Write Header
|
|
150
143
|
const reportRef = db.collection('computation_build_records').doc(buildId);
|
|
151
|
-
await reportRef.set(
|
|
144
|
+
await reportRef.set(reportHeader);
|
|
145
|
+
|
|
146
|
+
// 2. Batch Write Details (Using FirestoreUtils to handle batching constraints)
|
|
147
|
+
if (detailWrites.length > 0) {
|
|
148
|
+
logger.log('INFO', `[BuildReporter] Writing ${detailWrites.length} detail records...`);
|
|
149
|
+
await commitBatchInChunks(config, dependencies, detailWrites, 'BuildReportDetails');
|
|
150
|
+
}
|
|
152
151
|
|
|
153
|
-
//
|
|
154
|
-
await db.collection('computation_build_records').doc('latest').set({ ...
|
|
152
|
+
// 3. Update 'latest' pointer (Summary only)
|
|
153
|
+
await db.collection('computation_build_records').doc('latest').set({ ...reportHeader, note: "Latest build report pointer (See subcollection for details)." });
|
|
155
154
|
|
|
156
155
|
logger.log('SUCCESS', `[BuildReporter] Report ${buildId} saved. Re-runs: ${totalReRuns}, New: ${totalNew}.`);
|
|
157
156
|
|
|
158
157
|
return {
|
|
159
158
|
success: true,
|
|
160
159
|
reportId: buildId,
|
|
161
|
-
summary:
|
|
160
|
+
summary: reportHeader.summary
|
|
162
161
|
};
|
|
163
162
|
}
|
|
164
163
|
|