bulltrackers-module 1.0.440 → 1.0.441

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.
@@ -275,17 +275,52 @@ async function getPiFetchStatus(req, res, dependencies, config) {
275
275
 
276
276
  if (!requestsSnapshot.empty) {
277
277
  const latestRequest = requestsSnapshot.docs[0].data();
278
- const status = latestRequest.status || 'queued';
278
+ let status = latestRequest.status || 'queued';
279
+
280
+ // If status is 'indexing' or 'computing', check if computation results are now available
281
+ if (status === 'indexing' || status === 'computing') {
282
+ // Re-check if computation results exist
283
+ const checkDate = new Date();
284
+ for (let i = 0; i < 2; i++) { // Check today and yesterday
285
+ const dateStr = new Date(checkDate);
286
+ dateStr.setDate(checkDate.getDate() - i);
287
+ const dateStrFormatted = dateStr.toISOString().split('T')[0];
288
+
289
+ const docRef = db.collection(insightsCollection)
290
+ .doc(dateStrFormatted)
291
+ .collection(resultsSub)
292
+ .doc('popular-investor')
293
+ .collection(compsSub)
294
+ .doc('PopularInvestorProfileMetrics');
295
+
296
+ const doc = await docRef.get();
297
+ if (doc.exists) {
298
+ const { tryDecompress } = require('./data_helpers');
299
+ const data = tryDecompress(doc.data());
300
+
301
+ if (data && data[String(piCidNum)]) {
302
+ // Computation completed! Update status
303
+ status = 'completed';
304
+ await requestsSnapshot.docs[0].ref.update({
305
+ status: 'completed',
306
+ completedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp(),
307
+ updatedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp()
308
+ });
309
+ break;
310
+ }
311
+ }
312
+ }
313
+ }
279
314
 
280
315
  const response = {
281
316
  success: true,
282
- dataAvailable: false,
317
+ dataAvailable: status === 'completed',
283
318
  status,
284
319
  requestId: latestRequest.requestId,
285
320
  startedAt: latestRequest.startedAt?.toDate?.()?.toISOString() || null,
286
321
  createdAt: latestRequest.createdAt?.toDate?.()?.toISOString() || null,
287
322
  estimatedCompletion: latestRequest.startedAt
288
- ? new Date(new Date(latestRequest.startedAt.toDate()).getTime() + 5 * 60 * 1000).toISOString()
323
+ ? new Date(new Date(latestRequest.startedAt.toDate()).getTime() + 10 * 60 * 1000).toISOString() // 10 min for computation
289
324
  : null
290
325
  };
291
326
 
@@ -295,6 +330,12 @@ async function getPiFetchStatus(req, res, dependencies, config) {
295
330
  response.failedAt = latestRequest.failedAt?.toDate?.()?.toISOString() || null;
296
331
  }
297
332
 
333
+ // Include raw data status if computing
334
+ if (status === 'computing') {
335
+ response.rawDataStoredAt = latestRequest.rawDataStoredAt?.toDate?.()?.toISOString() || null;
336
+ response.message = 'Raw data stored, computation in progress...';
337
+ }
338
+
298
339
  return res.status(200).json(response);
299
340
  }
300
341
 
@@ -19,7 +19,7 @@ const { shouldTryProxy, recordProxyOutcome, getFailureCount, getMaxFailures } =
19
19
  * @param {object} dependencies - db, logger, proxyManager, batchManager, headerManager.
20
20
  */
21
21
  async function handlePopularInvestorUpdate(taskData, config, dependencies) {
22
- const { logger, proxyManager, batchManager, headerManager, db } = dependencies;
22
+ const { logger, proxyManager, batchManager, headerManager, db, pubsub } = dependencies;
23
23
 
24
24
  // Validate taskData exists and has required fields
25
25
  if (!taskData) {
@@ -299,7 +299,7 @@ async function handlePopularInvestorUpdate(taskData, config, dependencies) {
299
299
 
300
300
  logger.log('SUCCESS', `[PI Update] Completed full update for ${username}`);
301
301
 
302
- // Update request status to completed if this is an on-demand request
302
+ // Update request status and trigger computation if this is an on-demand request
303
303
  if (requestId && source === 'on_demand' && db) {
304
304
  try {
305
305
  const requestRef = db.collection('pi_fetch_requests')
@@ -307,13 +307,82 @@ async function handlePopularInvestorUpdate(taskData, config, dependencies) {
307
307
  .collection('requests')
308
308
  .doc(requestId);
309
309
 
310
+ // Update status to indicate raw data is stored, indexing and computation will be triggered
310
311
  await requestRef.update({
311
- status: 'completed',
312
- completedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp(),
312
+ status: 'indexing',
313
+ rawDataStoredAt: require('@google-cloud/firestore').FieldValue.serverTimestamp(),
313
314
  updatedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp()
314
315
  });
316
+
317
+ // CRITICAL: Trigger root data indexer FIRST so computation system knows data exists
318
+ try {
319
+ const { runRootDataIndexer } = require('../../root-data-indexer/index');
320
+ const indexerConfig = {
321
+ availabilityCollection: config.rootDataIndexer?.availabilityCollection || 'system_root_data_index',
322
+ earliestDate: config.rootDataIndexer?.earliestDate || '2025-08-01',
323
+ collections: config.rootDataIndexer?.collections || {},
324
+ targetDate: today // Index only today's date for speed
325
+ };
326
+
327
+ logger.log('INFO', `[PI Update] Triggering root data indexer for date ${today} before computation...`);
328
+ await runRootDataIndexer(indexerConfig, dependencies);
329
+ logger.log('INFO', `[PI Update] Root data indexer completed for date ${today}`);
330
+
331
+ // Update status to indicate indexing is done, computation is being triggered
332
+ await requestRef.update({
333
+ status: 'computing',
334
+ indexedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp(),
335
+ updatedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp()
336
+ });
337
+ } catch (indexerError) {
338
+ logger.log('ERROR', `[PI Update] Failed to run root data indexer for ${today}`, indexerError);
339
+ // Continue anyway - computation might still work if index already exists
340
+ // But update status to indicate we tried
341
+ await requestRef.update({
342
+ status: 'computing',
343
+ indexerError: indexerError.message,
344
+ updatedAt: require('@google-cloud/firestore').FieldValue.serverTimestamp()
345
+ });
346
+ }
347
+
348
+ // Trigger computation for PopularInvestorProfileMetrics
349
+ const { pubsub } = dependencies;
350
+ if (pubsub) {
351
+ const computationTopic = config.computationSystem?.computationTopicStandard || 'computation-tasks';
352
+ const topic = pubsub.topic(computationTopic);
353
+ const crypto = require('crypto');
354
+
355
+ const computationMessage = {
356
+ action: 'RUN_COMPUTATION_DATE',
357
+ computation: 'PopularInvestorProfileMetrics',
358
+ date: today,
359
+ pass: '1', // Standard pass
360
+ dispatchId: crypto.randomUUID(),
361
+ triggerReason: 'on_demand_pi_fetch',
362
+ resources: 'standard',
363
+ metadata: {
364
+ onDemand: true,
365
+ requestId: requestId,
366
+ piCid: cid,
367
+ piUsername: username
368
+ },
369
+ traceContext: {
370
+ traceId: crypto.randomBytes(16).toString('hex'),
371
+ spanId: crypto.randomBytes(8).toString('hex'),
372
+ sampled: true
373
+ }
374
+ };
375
+
376
+ await topic.publishMessage({
377
+ data: Buffer.from(JSON.stringify(computationMessage))
378
+ });
379
+
380
+ logger.log('INFO', `[PI Update] Triggered computation PopularInvestorProfileMetrics for PI ${cid} (${username}) for date ${today}`);
381
+ } else {
382
+ logger.log('WARN', `[PI Update] PubSub not available, cannot trigger computation`);
383
+ }
315
384
  } catch (err) {
316
- logger.log('WARN', `[PI Update] Failed to update request status to completed for ${requestId}`, err);
385
+ logger.log('WARN', `[PI Update] Failed to update request status or trigger computation for ${requestId}`, err);
317
386
  }
318
387
  }
319
388
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.440",
3
+ "version": "1.0.441",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [