bulltrackers-module 1.0.542 → 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.
@@ -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 = latestRequest.error || 'Unknown error occurred';
364
- response.failedAt = latestRequest.failedAt?.toDate?.()?.toISOString() || null;
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
- // Increased timeout to 15 minutes to account for computation time
323
- const STALE_THRESHOLD_MS = 15 * 60 * 1000; // 15 minutes
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.542",
3
+ "version": "1.0.543",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [