bulltrackers-module 1.0.475 → 1.0.477

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.
@@ -84,7 +84,10 @@ function resolveDependencyChain(computationName, manifest) {
84
84
  */
85
85
  async function triggerComputationWithDependencies(targetComputation, date, dependencies, config, metadata = {}) {
86
86
  const { pubsub, logger } = dependencies;
87
- const computationTopic = config.computationTopicStandard || 'computation-tasks';
87
+ // Use on-demand topic for on-demand computation requests
88
+ const computationTopic = config.computationTopicOnDemand ||
89
+ (config.getComputationTopic && config.getComputationTopic(true)) ||
90
+ 'computation-tasks-ondemand';
88
91
  const topic = pubsub.topic(computationTopic);
89
92
  const crypto = require('crypto');
90
93
 
@@ -1,6 +1,7 @@
1
- # Data Feeder Pipeline (V3.1 - Syntax Fixed)
1
+ # Data Feeder Pipeline (V3.2 - Automatic Root Data Indexing)
2
2
  # Starts at 22:00 UTC via Cloud Scheduler.
3
- # Fixes: Split assign/call steps and corrected assign syntax.
3
+ # UPDATED: Removed intermediate root data indexer calls - each fetcher now automatically triggers indexing.
4
+ # Only the global verification run at midnight remains.
4
5
 
5
6
  main:
6
7
  params: [input]
@@ -45,17 +46,7 @@ main:
45
46
  - wait_10_after_price:
46
47
  call: sys.sleep
47
48
  args: { seconds: 600 } # 10 Minutes
48
-
49
- # FIX 1: Split assign and call
50
- - prepare_index_price:
51
- assign:
52
- - today: '${text.split(time.format(sys.now()), "T")[0]}'
53
- - index_today_after_price:
54
- call: http.post
55
- args:
56
- url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
57
- body: { targetDate: '${today}' }
58
- auth: { type: OIDC }
49
+ # NOTE: Price fetcher now automatically triggers root data indexer after completion
59
50
 
60
51
  - wait_10_before_insights:
61
52
  call: sys.sleep
@@ -78,17 +69,7 @@ main:
78
69
  - wait_10_after_insights:
79
70
  call: sys.sleep
80
71
  args: { seconds: 600 }
81
-
82
- # FIX 2: Split assign and call
83
- - prepare_index_insights:
84
- assign:
85
- - today: '${text.split(time.format(sys.now()), "T")[0]}'
86
- - index_today_after_insights:
87
- call: http.post
88
- args:
89
- url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
90
- body: { targetDate: '${today}' }
91
- auth: { type: OIDC }
72
+ # NOTE: Insights fetcher now automatically triggers root data indexer after completion
92
73
 
93
74
  # ==========================================
94
75
  # PHASE 2: WAIT FOR MIDNIGHT
@@ -124,17 +105,7 @@ main:
124
105
  - wait_10_after_rankings:
125
106
  call: sys.sleep
126
107
  args: { seconds: 600 }
127
-
128
- # FIX 3: Split assign and call
129
- - prepare_index_rankings:
130
- assign:
131
- - today: '${text.split(time.format(sys.now()), "T")[0]}'
132
- - index_today_after_rankings:
133
- call: http.post
134
- args:
135
- url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
136
- body: { targetDate: '${today}' }
137
- auth: { type: OIDC }
108
+ # NOTE: Popular investor rankings fetcher now automatically triggers root data indexer after completion
138
109
 
139
110
  - phase_0000_social:
140
111
  try:
@@ -158,7 +129,7 @@ main:
158
129
  call: http.post
159
130
  args:
160
131
  url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
161
- # No targetDate = Global Run
132
+ # No targetDate = Global verification run (all intermediate indexing is now automatic)
162
133
  auth: { type: OIDC }
163
134
 
164
135
  # ==========================================
@@ -194,17 +165,7 @@ main:
194
165
  - wait_10_in_loop:
195
166
  call: sys.sleep
196
167
  args: { seconds: 600 }
197
-
198
- # FIX 4: Split assign and call
199
- - prepare_index_loop:
200
- assign:
201
- - today: '${text.split(time.format(sys.now()), "T")[0]}'
202
- - index_today_in_loop:
203
- call: http.post
204
- args:
205
- url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
206
- body: { targetDate: '${today}' }
207
- auth: { type: OIDC }
168
+ # NOTE: Social tasks are handled by task engine, which automatically triggers root data indexer after batch completion
208
169
 
209
170
  # FIX 5: Correct assign syntax (must be a list)
210
171
  - increment_loop:
@@ -113,6 +113,37 @@ async function fetchAndStorePopularInvestors(config, dependencies) {
113
113
  });
114
114
 
115
115
  logger.log('SUCCESS', `[PopularInvestorFetch] Stored ${data.TotalRows} rankings into ${rankingsCollectionName}/${today}`);
116
+
117
+ // Update root data indexer for today's date after rankings data is stored
118
+ try {
119
+ const { runRootDataIndexer } = require('../../root-data-indexer/index');
120
+ // Access rootDataIndexer from config (passed from index.js) or use defaults
121
+ // Using bracket notation to avoid TypeScript errors
122
+ let rootDataIndexerConfig;
123
+ if (config && typeof config === 'object' && config['rootDataIndexer']) {
124
+ rootDataIndexerConfig = config['rootDataIndexer'];
125
+ } else {
126
+ rootDataIndexerConfig = {
127
+ availabilityCollection: 'system_root_data_index',
128
+ earliestDate: '2025-08-01',
129
+ collections: {
130
+ piRankings: rankingsCollectionName
131
+ }
132
+ };
133
+ }
134
+
135
+ const indexerConfig = Object.assign({}, rootDataIndexerConfig, {
136
+ targetDate: today // Index only today's date for speed
137
+ });
138
+
139
+ logger.log('INFO', `[PopularInvestorFetch] Triggering root data indexer for date ${today} after rankings data storage...`);
140
+ await runRootDataIndexer(indexerConfig, dependencies);
141
+ logger.log('INFO', `[PopularInvestorFetch] Root data indexer completed for date ${today}`);
142
+ } catch (indexerError) {
143
+ logger.log('ERROR', `[PopularInvestorFetch] Failed to run root data indexer for ${today}`, indexerError);
144
+ // Continue - rankings data is stored, indexer failure is non-critical
145
+ }
146
+
116
147
  return { success: true, count: data.TotalRows };
117
148
 
118
149
  } catch (dbError) {
@@ -134,8 +134,10 @@ async function requestPiFetch(req, res, dependencies, config) {
134
134
  updatedAt: FieldValue.serverTimestamp()
135
135
  }, { merge: true });
136
136
 
137
- // Publish to task engine
138
- const topicName = config.taskEngine?.PUBSUB_TOPIC_USER_FETCH || 'etoro-user-fetch-topic';
137
+ // Publish to task engine - use on-demand topic for API requests
138
+ const topicName = config.taskEngine?.PUBSUB_TOPIC_USER_FETCH_ONDEMAND ||
139
+ config.pubsubTopicUserFetchOnDemand ||
140
+ 'etoro-user-fetch-topic-ondemand';
139
141
  const topic = pubsub.topic(topicName);
140
142
 
141
143
  const message = {
@@ -148,8 +148,10 @@ async function requestUserSync(req, res, dependencies, config) {
148
148
  updatedAt: FieldValue.serverTimestamp()
149
149
  }, { merge: true });
150
150
 
151
- // Publish to task engine
152
- const topicName = config.taskEngine?.PUBSUB_TOPIC_USER_FETCH || 'etoro-user-fetch-topic';
151
+ // Publish to task engine - use on-demand topic for API requests
152
+ const topicName = config.taskEngine?.PUBSUB_TOPIC_USER_FETCH_ONDEMAND ||
153
+ config.pubsubTopicUserFetchOnDemand ||
154
+ 'etoro-user-fetch-topic-ondemand';
153
155
  const topic = pubsub.topic(topicName);
154
156
 
155
157
  const message = {
@@ -57,8 +57,12 @@ async function finalizeVerification(req, res, dependencies, config) {
57
57
  proxyConfig,
58
58
  headerConfig,
59
59
  pubsubTopicUserFetch,
60
+ pubsubTopicUserFetchOnDemand,
60
61
  pubsubTopicSocialFetch
61
62
  } = config;
63
+
64
+ // Use on-demand topic for user signup (API-triggered)
65
+ const taskEngineTopic = pubsubTopicUserFetchOnDemand || pubsubTopicUserFetch || 'etoro-user-fetch-topic-ondemand';
62
66
 
63
67
  if (!username) return res.status(400).json({ error: "Missing username." });
64
68
 
@@ -187,8 +191,8 @@ async function finalizeVerification(req, res, dependencies, config) {
187
191
 
188
192
  // Only trigger if user is public (has portfolio data)
189
193
  if (!isOptOut) {
190
- await pubsubUtils.publish(pubsubTopicUserFetch, unifiedTask);
191
- logger.log('INFO', `[Verification] Triggered unified data fetch (portfolio + social) for ${username} (${realCID})`);
194
+ await pubsubUtils.publish(taskEngineTopic, unifiedTask);
195
+ logger.log('INFO', `[Verification] Triggered unified data fetch (portfolio + social) for ${username} (${realCID}) via on-demand topic`);
192
196
  } else {
193
197
  // For private users, still fetch social data but no portfolio
194
198
  const socialOnlyTask = {
@@ -208,8 +212,8 @@ async function finalizeVerification(req, res, dependencies, config) {
208
212
  requestedAt: new Date().toISOString()
209
213
  }
210
214
  };
211
- await pubsubUtils.publish(pubsubTopicUserFetch, socialOnlyTask);
212
- logger.log('INFO', `[Verification] Triggered social-only fetch for private user ${username} (${realCID})`);
215
+ await pubsubUtils.publish(taskEngineTopic, socialOnlyTask);
216
+ logger.log('INFO', `[Verification] Triggered social-only fetch for private user ${username} (${realCID}) via on-demand topic`);
213
217
  }
214
218
 
215
219
  return res.status(200).json({
@@ -13,15 +13,19 @@ const { handleSocialFetch } = require('./helpers/social_helpers');
13
13
  const { executeTasks, prepareTaskBatches } = require('./utils/task_engine_utils');
14
14
 
15
15
  async function handleRequest(message, context, configObj, dependencies) {
16
- // Support both old format (single config) and new format (object with taskEngine, rootDataIndexer, and social)
16
+ // Support both old format (single config) and new format (object with taskEngine, rootDataIndexer, social, and computationSystem)
17
17
  const config = configObj.taskEngine || configObj; // Backward compatibility
18
18
  const rootDataIndexerConfig = configObj.rootDataIndexer;
19
19
  const socialConfig = configObj.social;
20
+ const computationSystemConfig = configObj.computationSystem;
20
21
 
21
- // Merge social config into main config for easy access
22
+ // Merge configs into main config for easy access
22
23
  if (socialConfig) {
23
24
  config.social = socialConfig;
24
25
  }
26
+ if (computationSystemConfig) {
27
+ config.computationSystem = computationSystemConfig;
28
+ }
25
29
  const { logger, batchManager, db } = dependencies;
26
30
 
27
31
  // [CRITICAL FIX] Max Age increased to 25m to match the larger dedup window.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.475",
3
+ "version": "1.0.477",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [