bulltrackers-module 1.0.541 → 1.0.543
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.
|
@@ -274,7 +274,8 @@ class StandardExecutor {
|
|
|
274
274
|
const targetUserType = metadata.userType;
|
|
275
275
|
// [NEW] Always load Global Helpers
|
|
276
276
|
const mappings = await loader.loadMappings();
|
|
277
|
-
|
|
277
|
+
// [FIX] Correct method name: loadPIMasterList (not loadPopularInvestorMasterList)
|
|
278
|
+
const piMasterList = await loader.loadPIMasterList();
|
|
278
279
|
const SCHEMAS = mathLayer.SCHEMAS;
|
|
279
280
|
|
|
280
281
|
// 1. Load Root Data
|
|
@@ -346,6 +346,86 @@ async function getPiFetchStatus(req, res, dependencies, config) {
|
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
// Check if request is stale (stuck in processing state for too long)
|
|
350
|
+
// Set to 2 minutes to prevent indefinite polling when computation system crashes
|
|
351
|
+
const { FieldValue } = require('@google-cloud/firestore');
|
|
352
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 1000; // 2 minutes
|
|
353
|
+
const processingStates = ['processing', 'dispatched', 'indexing', 'computing', 'queued'];
|
|
354
|
+
const isProcessingState = processingStates.includes(status);
|
|
355
|
+
|
|
356
|
+
let isStale = false;
|
|
357
|
+
if (isProcessingState) {
|
|
358
|
+
const now = Date.now();
|
|
359
|
+
const createdAt = latestRequest.createdAt?.toDate?.()?.getTime() ||
|
|
360
|
+
latestRequest.createdAt?.toMillis?.() || null;
|
|
361
|
+
const dispatchedAt = latestRequest.dispatchedAt?.toDate?.()?.getTime() ||
|
|
362
|
+
latestRequest.dispatchedAt?.toMillis?.() || null;
|
|
363
|
+
const startedAt = latestRequest.startedAt?.toDate?.()?.getTime() ||
|
|
364
|
+
latestRequest.startedAt?.toMillis?.() || null;
|
|
365
|
+
const updatedAt = latestRequest.updatedAt?.toDate?.()?.getTime() ||
|
|
366
|
+
latestRequest.updatedAt?.toMillis?.() || null;
|
|
367
|
+
|
|
368
|
+
// Use the most recent timestamp to determine age
|
|
369
|
+
const referenceTime = startedAt || dispatchedAt || createdAt || updatedAt;
|
|
370
|
+
|
|
371
|
+
if (referenceTime && (now - referenceTime) > STALE_THRESHOLD_MS) {
|
|
372
|
+
// Before marking as stale, do one final check for computation results
|
|
373
|
+
const finalCheckDate = new Date();
|
|
374
|
+
let foundResults = false;
|
|
375
|
+
for (let i = 0; i < 2; i++) {
|
|
376
|
+
const dateStr = new Date(finalCheckDate);
|
|
377
|
+
dateStr.setDate(finalCheckDate.getDate() - i);
|
|
378
|
+
const dateStrFormatted = dateStr.toISOString().split('T')[0];
|
|
379
|
+
|
|
380
|
+
const docRef = db.collection(insightsCollection)
|
|
381
|
+
.doc(dateStrFormatted)
|
|
382
|
+
.collection(resultsSub)
|
|
383
|
+
.doc('popular-investor')
|
|
384
|
+
.collection(compsSub)
|
|
385
|
+
.doc('PopularInvestorProfileMetrics');
|
|
386
|
+
|
|
387
|
+
const doc = await docRef.get();
|
|
388
|
+
if (doc.exists) {
|
|
389
|
+
const { tryDecompress } = require('../data_helpers');
|
|
390
|
+
const data = tryDecompress(doc.data());
|
|
391
|
+
if (data && typeof data === 'object' && data[String(piCidNum)]) {
|
|
392
|
+
foundResults = true;
|
|
393
|
+
status = 'completed';
|
|
394
|
+
await requestsSnapshot.docs[0].ref.update({
|
|
395
|
+
status: 'completed',
|
|
396
|
+
completedAt: FieldValue.serverTimestamp(),
|
|
397
|
+
updatedAt: FieldValue.serverTimestamp()
|
|
398
|
+
});
|
|
399
|
+
logger.log('INFO', `[getPiFetchStatus] Found computation results on stale check, marked as completed`);
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (!foundResults) {
|
|
406
|
+
isStale = true;
|
|
407
|
+
logger.log('WARN', `[getPiFetchStatus] Detected stale request ${latestRequest.requestId} for PI ${piCidNum}. Status: ${status}, Age: ${Math.round((now - referenceTime) / 60000)} minutes`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// If stale, mark as failed to stop polling
|
|
413
|
+
if (isStale) {
|
|
414
|
+
status = 'failed';
|
|
415
|
+
const requestDocRef = requestsSnapshot.docs[0].ref;
|
|
416
|
+
try {
|
|
417
|
+
await requestDocRef.update({
|
|
418
|
+
status: 'failed',
|
|
419
|
+
error: 'Request timed out - task may have failed to process. Please try again.',
|
|
420
|
+
failedAt: FieldValue.serverTimestamp(),
|
|
421
|
+
updatedAt: FieldValue.serverTimestamp()
|
|
422
|
+
});
|
|
423
|
+
logger.log('INFO', `[getPiFetchStatus] Marked stale request ${latestRequest.requestId} as failed`);
|
|
424
|
+
} catch (updateErr) {
|
|
425
|
+
logger.log('WARN', `[getPiFetchStatus] Failed to update stale request status`, updateErr);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
349
429
|
const response = {
|
|
350
430
|
success: true,
|
|
351
431
|
dataAvailable: status === 'completed',
|
|
@@ -360,8 +440,11 @@ async function getPiFetchStatus(req, res, dependencies, config) {
|
|
|
360
440
|
|
|
361
441
|
// Include error details if status is failed
|
|
362
442
|
if (status === 'failed') {
|
|
363
|
-
response.error =
|
|
364
|
-
|
|
443
|
+
response.error = isStale
|
|
444
|
+
? 'Request timed out - task may have failed to process. Please try again.'
|
|
445
|
+
: (latestRequest.error || 'Unknown error occurred');
|
|
446
|
+
response.failedAt = latestRequest.failedAt?.toDate?.()?.toISOString() ||
|
|
447
|
+
(isStale ? new Date().toISOString() : null);
|
|
365
448
|
}
|
|
366
449
|
|
|
367
450
|
// Include raw data status if computing
|
|
@@ -319,8 +319,8 @@ async function getUserSyncStatus(req, res, dependencies, config) {
|
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
// Check if request is stale (stuck in processing state for too long)
|
|
322
|
-
//
|
|
323
|
-
const STALE_THRESHOLD_MS =
|
|
322
|
+
// Set to 2 minutes to prevent indefinite polling when computation system crashes
|
|
323
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 1000; // 2 minutes
|
|
324
324
|
const processingStates = ['processing', 'dispatched', 'indexing', 'computing', 'queued'];
|
|
325
325
|
const isProcessingState = processingStates.includes(status);
|
|
326
326
|
|