bulltrackers-module 1.0.358 → 1.0.360
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.
|
@@ -2,17 +2,12 @@
|
|
|
2
2
|
* @fileoverview Core Firestore utility functions.
|
|
3
3
|
* REFACTORED: All functions are now stateless and receive dependencies.
|
|
4
4
|
* 'db' (Firestore instance) and 'logger' are passed via a 'dependencies' object.
|
|
5
|
+
* UPDATED: Added support for Popular Investor (Rankings) and Signed-In User fetching.
|
|
5
6
|
*/
|
|
6
7
|
const { FieldValue, FieldPath } = require('@google-cloud/firestore');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Fetches and merges the most recent portfolio data for all normal users.
|
|
10
|
-
* @param {object} dependencies - Contains db, logger.
|
|
11
|
-
* @param {object} config - Configuration object.
|
|
12
|
-
* @param {string} config.normalUserCollectionName - e.g., 'NormalUserPortfolios'.
|
|
13
|
-
* @param {string} config.snapshotsSubCollectionName - e.g., 'snapshots'.
|
|
14
|
-
* @param {string} config.partsSubCollectionName - e.g., 'parts'.
|
|
15
|
-
* @returns {Promise<object>} A single object containing all user portfolios.
|
|
16
11
|
*/
|
|
17
12
|
async function getLatestNormalUserPortfolios(dependencies, config) {
|
|
18
13
|
const { db, logger } = dependencies;
|
|
@@ -34,10 +29,6 @@ async function getLatestNormalUserPortfolios(dependencies, config) {
|
|
|
34
29
|
|
|
35
30
|
/**
|
|
36
31
|
* Resets the proxy locks map in the performance document.
|
|
37
|
-
* @param {object} dependencies - Contains db, logger.
|
|
38
|
-
* @param {object} config - Configuration object.
|
|
39
|
-
* @param {string} config.proxyPerformanceDocPath - e.g., 'system_state/proxy_performance'.
|
|
40
|
-
* @returns {Promise<void>}
|
|
41
32
|
*/
|
|
42
33
|
async function resetProxyLocks(dependencies, config) {
|
|
43
34
|
const { db, logger } = dependencies;
|
|
@@ -55,12 +46,6 @@ async function resetProxyLocks(dependencies, config) {
|
|
|
55
46
|
|
|
56
47
|
/**
|
|
57
48
|
* Fetches and aggregates block capacities.
|
|
58
|
-
* @param {object} dependencies - Contains db, logger.
|
|
59
|
-
* @param {object} config - Configuration object.
|
|
60
|
-
* @param {string} userType - 'normal' or 'speculator'.
|
|
61
|
-
* @param {string} config.speculatorBlockCountsDocPath - Path to speculator counts doc.
|
|
62
|
-
* @param {string} config.normalBlockCountsDocPath - Path to normal counts doc.
|
|
63
|
-
* @returns {Promise<object>} Object containing counts.
|
|
64
49
|
*/
|
|
65
50
|
async function getBlockCapacities(dependencies, config, userType) {
|
|
66
51
|
const { db, logger } = dependencies;
|
|
@@ -78,14 +63,6 @@ async function getBlockCapacities(dependencies, config, userType) {
|
|
|
78
63
|
|
|
79
64
|
/**
|
|
80
65
|
* Fetches user IDs from multiple sources for exclusion lists.
|
|
81
|
-
* @param {object} dependencies - Contains db, logger.
|
|
82
|
-
* @param {object} config - Configuration object.
|
|
83
|
-
* @param {string} userType - 'normal' or 'speculator'.
|
|
84
|
-
* @param {string} config.specBlocksCollection - e.g., 'SpeculatorBlocks'.
|
|
85
|
-
* @param {string} config.pendingSpecCollection - e.g., 'PendingSpeculators'.
|
|
86
|
-
* @param {string} config.invalidSpecCollection - e.g., 'InvalidSpeculators'.
|
|
87
|
-
* @param {Set<string>} config.existingNormalUserIds - PRE-FETCHED normal user IDs.
|
|
88
|
-
* @returns {Promise<Set<string>>} A Set containing unique user IDs.
|
|
89
66
|
*/
|
|
90
67
|
async function getExclusionIds(dependencies, config, userType) {
|
|
91
68
|
const { db, logger } = dependencies;
|
|
@@ -95,15 +72,12 @@ async function getExclusionIds(dependencies, config, userType) {
|
|
|
95
72
|
logger.log('TRACE', `[Core Utils] Loaded ${exclusionIds.size} existing normal user IDs for exclusion.`);
|
|
96
73
|
const promises = [];
|
|
97
74
|
try {
|
|
98
|
-
// 1. Existing Speculators
|
|
99
75
|
const specBlocksRef = db.collection(specBlocksCollection);
|
|
100
76
|
promises.push(specBlocksRef.get().then(snapshot => {snapshot.forEach(doc => {const users = doc.data().users || {}; Object.keys(users).forEach(key => exclusionIds.add(key.split('.')[1])); });
|
|
101
77
|
logger.log('TRACE','[Core Utils] Fetched existing speculator IDs for exclusion.');}));
|
|
102
|
-
// 2. Pending Speculators
|
|
103
78
|
if (userType === 'speculator') {const pendingRef = db.collection(pendingSpecCollection);
|
|
104
79
|
promises.push(pendingRef.get().then(snapshot => {snapshot.forEach(doc => {Object.keys(doc.data().users || {}).forEach(cid => exclusionIds.add(cid));});
|
|
105
80
|
logger.log('TRACE','[Core Utils] Fetched pending speculator IDs for exclusion.');})); }
|
|
106
|
-
// 3. Invalid Speculators
|
|
107
81
|
const invalidRef = db.collection(invalidSpecCollection);
|
|
108
82
|
promises.push(invalidRef.get().then(snapshot => { snapshot.forEach(doc => {const data = doc.data();if (data) {Object.keys(data.users || {}).forEach(cid => exclusionIds.add(cid));}});
|
|
109
83
|
logger.log('TRACE','[Core Utils] Fetched invalid speculator IDs for exclusion.');}));
|
|
@@ -117,11 +91,6 @@ async function getExclusionIds(dependencies, config, userType) {
|
|
|
117
91
|
|
|
118
92
|
/**
|
|
119
93
|
* Scans normal user portfolios for potential speculator candidates.
|
|
120
|
-
* @param {object} dependencies - Contains db, logger.
|
|
121
|
-
* @param {Set<string>} exclusionIds - IDs to exclude.
|
|
122
|
-
* @param {Set<number>} speculatorInstrumentSet - Set of instrument IDs.
|
|
123
|
-
* @param {object} latestNormalPortfolios - PRE-FETCHED portfolio object.
|
|
124
|
-
* @returns {Promise<string[]>} Array of prioritized speculator CIDs.
|
|
125
94
|
*/
|
|
126
95
|
async function getPrioritizedSpeculators(dependencies, exclusionIds, speculatorInstrumentSet, latestNormalPortfolios) {
|
|
127
96
|
const { logger } = dependencies;
|
|
@@ -143,10 +112,6 @@ async function getPrioritizedSpeculators(dependencies, exclusionIds, speculatorI
|
|
|
143
112
|
|
|
144
113
|
/**
|
|
145
114
|
* Deletes all documents within a specified collection path.
|
|
146
|
-
* @param {object} dependencies - Contains db, logger.
|
|
147
|
-
* @param {string} collectionPath - The path to the collection to clear.
|
|
148
|
-
* @param {number} maxBatchSize - Firestore batch size limit.
|
|
149
|
-
* @returns {Promise<void>}
|
|
150
115
|
*/
|
|
151
116
|
async function clearCollection(dependencies, collectionPath, maxBatchSize = 400) {
|
|
152
117
|
const { db, logger } = dependencies;
|
|
@@ -174,14 +139,6 @@ async function clearCollection(dependencies, collectionPath, maxBatchSize = 400)
|
|
|
174
139
|
|
|
175
140
|
/**
|
|
176
141
|
* Writes an array of user IDs into sharded Firestore documents.
|
|
177
|
-
* @param {object} dependencies - Contains db, logger.
|
|
178
|
-
* @param {object} config - Configuration object.
|
|
179
|
-
* @param {string} config.collectionPath - Base path for sharded documents (e.g., 'PendingSpeculators').
|
|
180
|
-
* @param {string[]} config.items - The user IDs to write.
|
|
181
|
-
* @param {Date} config.timestamp - Timestamp to associate with each user ID.
|
|
182
|
-
* @param {number} config.maxFieldsPerDoc - Max user IDs per sharded document.
|
|
183
|
-
* @param {number} config.maxWritesPerBatch - Max documents to write per batch commit.
|
|
184
|
-
* @returns {Promise<void>}
|
|
185
142
|
*/
|
|
186
143
|
async function batchWriteShardedIds(dependencies, config) {
|
|
187
144
|
const { db, logger } = dependencies;
|
|
@@ -219,12 +176,6 @@ async function batchWriteShardedIds(dependencies, config) {
|
|
|
219
176
|
|
|
220
177
|
/**
|
|
221
178
|
* Gets normal users whose timestamp indicates they need updating.
|
|
222
|
-
* @param {object} dependencies - Contains db, logger.
|
|
223
|
-
* @param {object} config - Configuration object.
|
|
224
|
-
* @param {Date} config.dateThreshold - Users processed before this date will be returned.
|
|
225
|
-
* @param {string} config.normalUserCollectionName - e.g., 'NormalUserPortfolios'.
|
|
226
|
-
* @param {string} config.normalUserTimestampsDocId - e.g., 'normal'.
|
|
227
|
-
* @returns {Promise<string[]>} Array of user IDs to update.
|
|
228
179
|
*/
|
|
229
180
|
async function getNormalUsersToUpdate(dependencies, config) {
|
|
230
181
|
const { db, logger } = dependencies;
|
|
@@ -248,12 +199,6 @@ async function getNormalUsersToUpdate(dependencies, config) {
|
|
|
248
199
|
|
|
249
200
|
/**
|
|
250
201
|
* Gets speculator users/instruments whose data needs updating.
|
|
251
|
-
* @param {object} dependencies - Contains db, logger.
|
|
252
|
-
* @param {object} config - Configuration object.
|
|
253
|
-
* @param {Date} config.dateThreshold - Verification date threshold.
|
|
254
|
-
* @param {Date} config.gracePeriodThreshold - Last held asset date threshold.
|
|
255
|
-
* @param {string} config.speculatorBlocksCollectionName - e.g., 'SpeculatorBlocks'.
|
|
256
|
-
* @returns {Promise<object[]>} Array of objects like { userId: string, instrumentId: number }.
|
|
257
202
|
*/
|
|
258
203
|
async function getSpeculatorsToUpdate(dependencies, config) {
|
|
259
204
|
const { db, logger } = dependencies;
|
|
@@ -281,4 +226,93 @@ async function getSpeculatorsToUpdate(dependencies, config) {
|
|
|
281
226
|
} catch (error) { logger.log('ERROR','[Core Utils] Error getting speculators to update', { errorMessage: error.message }); throw error; }
|
|
282
227
|
}
|
|
283
228
|
|
|
284
|
-
|
|
229
|
+
/**
|
|
230
|
+
* [NEW] Fetches Popular Investors from the daily rankings document.
|
|
231
|
+
*/
|
|
232
|
+
async function getPopularInvestorsToUpdate(dependencies, config) {
|
|
233
|
+
const { db, logger } = dependencies;
|
|
234
|
+
const collectionName = config.popularInvestorRankingsCollection || process.env.FIRESTORE_COLLECTION_PI_RANKINGS || 'popular_investor_rankings';
|
|
235
|
+
|
|
236
|
+
logger.log('INFO', `[Core Utils] Getting Popular Investors to update from ${collectionName}...`);
|
|
237
|
+
|
|
238
|
+
// Construct today's document ID (YYYY-MM-DD)
|
|
239
|
+
const today = new Date().toISOString().split('T')[0];
|
|
240
|
+
const docPath = `${collectionName}/${today}`;
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
const docRef = db.doc(docPath);
|
|
244
|
+
const docSnap = await docRef.get();
|
|
245
|
+
|
|
246
|
+
if (!docSnap.exists) {
|
|
247
|
+
logger.log('WARN', `[Core Utils] No Popular Investor rankings found for date: ${today} at ${docPath}`);
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const data = docSnap.data();
|
|
252
|
+
const items = data.Items || [];
|
|
253
|
+
|
|
254
|
+
// Map to { cid, username }
|
|
255
|
+
const targets = items.map(item => ({
|
|
256
|
+
cid: String(item.CustomerId),
|
|
257
|
+
username: item.UserName
|
|
258
|
+
}));
|
|
259
|
+
|
|
260
|
+
logger.log('INFO', `[Core Utils] Found ${targets.length} Popular Investors from ${today} ranking.`);
|
|
261
|
+
return targets;
|
|
262
|
+
|
|
263
|
+
} catch (error) {
|
|
264
|
+
logger.log('ERROR', '[Core Utils] Error getting Popular Investors', { errorMessage: error.message });
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* [NEW] Fetches all Signed-In Users for daily update.
|
|
271
|
+
*/
|
|
272
|
+
async function getSignedInUsersToUpdate(dependencies, config) {
|
|
273
|
+
const { db, logger } = dependencies;
|
|
274
|
+
const collectionName = config.signedInUsersCollection || process.env.FIRESTORE_COLLECTION_SIGNED_IN_USER_PORTFOLIOS || 'signed_in_users';
|
|
275
|
+
|
|
276
|
+
logger.log('INFO', `[Core Utils] Getting Signed-In Users to update from ${collectionName}...`);
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
const snapshot = await db.collection(collectionName).get();
|
|
280
|
+
|
|
281
|
+
if (snapshot.empty) {
|
|
282
|
+
logger.log('INFO', '[Core Utils] No Signed-In Users found.');
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const targets = [];
|
|
287
|
+
snapshot.forEach(doc => {
|
|
288
|
+
const data = doc.data();
|
|
289
|
+
// Assuming the doc ID is the CID, or it's a field 'cid'
|
|
290
|
+
const cid = data.cid || doc.id;
|
|
291
|
+
const username = data.username || 'Unknown';
|
|
292
|
+
// Only push if we have a valid CID
|
|
293
|
+
if(cid) targets.push({ cid: String(cid), username });
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
logger.log('INFO', `[Core Utils] Found ${targets.length} Signed-In Users.`);
|
|
297
|
+
return targets;
|
|
298
|
+
|
|
299
|
+
} catch (error) {
|
|
300
|
+
logger.log('ERROR', '[Core Utils] Error getting Signed-In Users', { errorMessage: error.message });
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
module.exports = {
|
|
306
|
+
getLatestNormalUserPortfolios,
|
|
307
|
+
resetProxyLocks,
|
|
308
|
+
getBlockCapacities,
|
|
309
|
+
getExclusionIds,
|
|
310
|
+
getPrioritizedSpeculators,
|
|
311
|
+
clearCollection,
|
|
312
|
+
batchWriteShardedIds,
|
|
313
|
+
getNormalUsersToUpdate,
|
|
314
|
+
getSpeculatorsToUpdate,
|
|
315
|
+
// New Exports
|
|
316
|
+
getPopularInvestorsToUpdate,
|
|
317
|
+
getSignedInUsersToUpdate
|
|
318
|
+
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Sub-pipe: pipe.orchestrator.getUpdateTargets
|
|
8
|
-
* @param {string} userType - 'normal' or '
|
|
8
|
+
* @param {string} userType - 'normal', 'speculator', 'popular_investor', or 'signed_in_user'.
|
|
9
9
|
* @param {object} thresholds - Contains date thresholds.
|
|
10
10
|
* @param {object} config - The *global* updateConfig object.
|
|
11
11
|
* @param {object} dependencies - Contains db, pubsub, logger, firestoreUtils.
|
|
@@ -16,24 +16,39 @@ async function getUpdateTargets(userType, thresholds, config, dependencies) {
|
|
|
16
16
|
logger.log('INFO', `[Orchestrator Helpers] Getting update targets for ${userType}...`);
|
|
17
17
|
let targets = [];
|
|
18
18
|
try {
|
|
19
|
-
if (userType === 'normal') {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
if (userType === 'normal') {
|
|
20
|
+
targets = await firestoreUtils.getNormalUsersToUpdate(dependencies,{
|
|
21
|
+
dateThreshold: thresholds.dateThreshold,
|
|
22
|
+
normalUserCollectionName: config.normalUserCollectionName,
|
|
23
|
+
normalUserTimestampsDocId: config.normalUserTimestampsDocId
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else if (userType === 'speculator') {
|
|
27
|
+
targets = await firestoreUtils.getSpeculatorsToUpdate(dependencies,{
|
|
28
|
+
dateThreshold: thresholds.dateThreshold,
|
|
29
|
+
gracePeriodThreshold: thresholds.gracePeriodThreshold,
|
|
30
|
+
speculatorBlocksCollectionName: config.speculatorBlocksCollectionName
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else if (userType === 'popular_investor') {
|
|
34
|
+
targets = await firestoreUtils.getPopularInvestorsToUpdate(dependencies, config);
|
|
35
|
+
}
|
|
36
|
+
else if (userType === 'signed_in_user') {
|
|
37
|
+
targets = await firestoreUtils.getSignedInUsersToUpdate(dependencies, config);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
logger.log('SUCCESS', `[Orchestrator Helpers] Found ${targets.length} targets for ${userType} update.`);
|
|
41
|
+
return targets;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
logger.log('ERROR', `[Orchestrator Helpers] Error getting update targets for ${userType}`, { errorMessage: error.message });
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
31
46
|
}
|
|
32
47
|
|
|
33
48
|
/**
|
|
34
49
|
* Sub-pipe: pipe.orchestrator.dispatchUpdates
|
|
35
50
|
* @param {Array<any>} targets - Array of targets from getUpdateTargets.
|
|
36
|
-
* @param {string} userType - 'normal' or '
|
|
51
|
+
* @param {string} userType - 'normal', 'speculator', 'popular_investor', or 'signed_in_user'.
|
|
37
52
|
* @param {object} config - The *global* updateConfig object.
|
|
38
53
|
* @param {object} dependencies - Contains db, pubsub, logger, pubsubUtils.
|
|
39
54
|
* @returns {Promise<void>}
|
|
@@ -41,11 +56,43 @@ async function getUpdateTargets(userType, thresholds, config, dependencies) {
|
|
|
41
56
|
async function dispatchUpdates(targets, userType, config, dependencies) {
|
|
42
57
|
const { logger, pubsubUtils } = dependencies;
|
|
43
58
|
const { dispatcherTopicName, taskBatchSize, pubsubBatchSize } = config;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
|
|
60
|
+
if (targets.length === 0) {
|
|
61
|
+
logger.log('INFO', `[Orchestrator Helpers] No ${userType} update targets to dispatch.`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
logger.log('INFO', `[Orchestrator Helpers] Dispatching ${targets.length} update tasks for ${userType} to ${dispatcherTopicName}...`);
|
|
66
|
+
|
|
67
|
+
const individualTasks = targets.map(target => {
|
|
68
|
+
if (userType === 'normal') {
|
|
69
|
+
return { type: 'update', userId: target, userType };
|
|
70
|
+
} else if (userType === 'speculator') {
|
|
71
|
+
return { type: 'update', userId: target.userId, instruments: target.instruments, userType };
|
|
72
|
+
} else if (userType === 'popular_investor') {
|
|
73
|
+
return { type: 'POPULAR_INVESTOR_UPDATE', cid: target.cid, username: target.username };
|
|
74
|
+
} else if (userType === 'signed_in_user') {
|
|
75
|
+
return { type: 'ON_DEMAND_USER_UPDATE', cid: target.cid, username: target.username };
|
|
76
|
+
}
|
|
77
|
+
});
|
|
50
78
|
|
|
51
|
-
|
|
79
|
+
const dispatcherMessages = [];
|
|
80
|
+
for (let i = 0; i < individualTasks.length; i += taskBatchSize) {
|
|
81
|
+
dispatcherMessages.push({ tasks: individualTasks.slice(i, i + taskBatchSize) });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await pubsubUtils.batchPublishTasks(dependencies,{
|
|
86
|
+
topicName: dispatcherTopicName,
|
|
87
|
+
tasks: dispatcherMessages,
|
|
88
|
+
taskType: `${userType} update batch`,
|
|
89
|
+
maxPubsubBatchSize: pubsubBatchSize
|
|
90
|
+
});
|
|
91
|
+
logger.log('SUCCESS', `[Orchestrator Helpers] Published ${dispatcherMessages.length} messages (${individualTasks.length} tasks) for ${userType} updates to the dispatcher.`);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logger.log('ERROR', `[Orchestrator Helpers] Error dispatching update tasks for ${userType}`, { errorMessage: error.message });
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { getUpdateTargets, dispatchUpdates };
|
|
@@ -21,8 +21,34 @@ async function runUpdateOrchestrator(config, deps) {
|
|
|
21
21
|
const { logger, firestoreUtils } = deps;
|
|
22
22
|
logger.log('INFO', '🚀 Update Orchestrator triggered...');
|
|
23
23
|
await firestoreUtils.resetProxyLocks(deps, config);
|
|
24
|
+
|
|
25
|
+
// 1. Normal Users
|
|
24
26
|
await runUpdates('normal', config.updateConfig, config, deps);
|
|
27
|
+
|
|
28
|
+
// 2. Speculators
|
|
25
29
|
await runUpdates('speculator', config.updateConfig, config, deps);
|
|
30
|
+
|
|
31
|
+
// 3. Popular Investors
|
|
32
|
+
try {
|
|
33
|
+
const piConfig = {
|
|
34
|
+
...config.updateConfig,
|
|
35
|
+
popularInvestorRankingsCollection: config.updateConfig.popularInvestorRankingsCollection || process.env.FIRESTORE_COLLECTION_PI_RANKINGS || 'popular_investor_rankings'
|
|
36
|
+
};
|
|
37
|
+
await runUpdates('popular_investor', piConfig, config, deps);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
logger.log('ERROR', '[Orchestrator] Failed to run Popular Investor updates.', e);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 4. Signed-In Users
|
|
43
|
+
try {
|
|
44
|
+
const signedInConfig = {
|
|
45
|
+
...config.updateConfig,
|
|
46
|
+
signedInUsersCollection: config.updateConfig.signedInUsersCollection || process.env.FIRESTORE_COLLECTION_SIGNED_IN_USER_PORTFOLIOS || 'signed_in_users'
|
|
47
|
+
};
|
|
48
|
+
await runUpdates('signed_in_user', signedInConfig, config, deps);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
logger.log('ERROR', '[Orchestrator] Failed to run Signed-In User updates.', e);
|
|
51
|
+
}
|
|
26
52
|
}
|
|
27
53
|
|
|
28
54
|
/** Stage 3: Run discovery for a single user type */
|
|
@@ -61,4 +87,4 @@ async function runUpdates(userType, updateConfig, globalConfig, deps) {
|
|
|
61
87
|
logger.log('SUCCESS', `[Orchestrator] Dispatched update tasks for ${userType}.`);
|
|
62
88
|
}
|
|
63
89
|
|
|
64
|
-
module.exports = { runDiscoveryOrchestrator, runUpdateOrchestrator, runDiscovery, runUpdates };
|
|
90
|
+
module.exports = { runDiscoveryOrchestrator, runUpdateOrchestrator, runDiscovery, runUpdates };
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Main entry point for the Task Engine Cloud Function.
|
|
3
|
-
* Routes incoming Pub/Sub messages to the appropriate helper functions.
|
|
4
3
|
*/
|
|
5
4
|
const { handleDiscover } = require('./helpers/discover_helpers');
|
|
6
5
|
const { handleVerify } = require('./helpers/verify_helpers');
|
|
7
|
-
const { handleUpdate } = require('./helpers/update_helpers');
|
|
6
|
+
const { handleUpdate } = require('./helpers/update_helpers');
|
|
8
7
|
const { handlePopularInvestorUpdate, handleOnDemandUserUpdate } = require('./helpers/popular_investor_helpers');
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* @param {object} context - The event context.
|
|
14
|
-
* @param {object} config - The Task Engine configuration.
|
|
15
|
-
* @param {object} dependencies - Injected dependencies (db, logger, proxyManager, etc.).
|
|
16
|
-
*/
|
|
9
|
+
// IMPORT THE UTILS TO HANDLE BATCHES
|
|
10
|
+
const { executeTasks, prepareTaskBatches } = require('./utils/task_engine_utils');
|
|
11
|
+
|
|
17
12
|
async function handleRequest(message, context, config, dependencies) {
|
|
18
13
|
const { logger } = dependencies;
|
|
19
14
|
|
|
@@ -27,12 +22,27 @@ async function handleRequest(message, context, config, dependencies) {
|
|
|
27
22
|
return;
|
|
28
23
|
}
|
|
29
24
|
|
|
25
|
+
// --- FIX START: Handle Batch vs Single ---
|
|
26
|
+
|
|
27
|
+
// CASE A: Payload is a Batch (from Dispatcher)
|
|
28
|
+
if (payload.tasks && Array.isArray(payload.tasks)) {
|
|
29
|
+
logger.log('INFO', `[TaskEngine] Received BATCH of ${payload.tasks.length} tasks.`);
|
|
30
|
+
const taskId = context.eventId || 'batch-' + Date.now();
|
|
31
|
+
|
|
32
|
+
// Use existing utils to execute the batch
|
|
33
|
+
const { tasksToRun, otherTasks } = await prepareTaskBatches(payload.tasks, null, logger);
|
|
34
|
+
await executeTasks(tasksToRun, otherTasks, dependencies, config, taskId);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// CASE B: Payload is a Single Task (from Cron/On-Demand)
|
|
30
39
|
const { type, data } = payload;
|
|
31
40
|
|
|
32
41
|
if (!type) {
|
|
33
42
|
logger.log('WARN', '[TaskEngine] Received message with no type.', payload);
|
|
34
43
|
return;
|
|
35
44
|
}
|
|
45
|
+
// --- FIX END ---
|
|
36
46
|
|
|
37
47
|
logger.log('INFO', `[TaskEngine] Processing Task: ${type}`, { dataSummary: JSON.stringify(data).substring(0, 100) });
|
|
38
48
|
|
|
@@ -40,23 +50,18 @@ async function handleRequest(message, context, config, dependencies) {
|
|
|
40
50
|
try {
|
|
41
51
|
switch (type) {
|
|
42
52
|
case 'DISCOVER':
|
|
43
|
-
await handleDiscover(data,
|
|
53
|
+
await handleDiscover(data, 'single-discover', dependencies, config); // Added taskId arg
|
|
44
54
|
break;
|
|
45
55
|
case 'VERIFY':
|
|
46
|
-
await handleVerify(data,
|
|
56
|
+
await handleVerify(data, 'single-verify', dependencies, config); // Added taskId arg
|
|
47
57
|
break;
|
|
48
58
|
case 'UPDATE':
|
|
49
|
-
|
|
50
|
-
await handleUpdate(data, config, dependencies);
|
|
59
|
+
await handleUpdate(data, 'single-update', dependencies, config); // Added taskId arg
|
|
51
60
|
break;
|
|
52
61
|
case 'POPULAR_INVESTOR_UPDATE':
|
|
53
|
-
// New logic for Popular Investors (daily cron, high fidelity)
|
|
54
|
-
// data should contain { cid, username }
|
|
55
62
|
await handlePopularInvestorUpdate(data, config, dependencies);
|
|
56
63
|
break;
|
|
57
64
|
case 'ON_DEMAND_USER_UPDATE':
|
|
58
|
-
// New logic for Signed-In Users (immediate trigger, cost optimized)
|
|
59
|
-
// data should contain { cid, username }
|
|
60
65
|
await handleOnDemandUserUpdate(data, config, dependencies);
|
|
61
66
|
break;
|
|
62
67
|
default:
|
|
@@ -64,8 +69,6 @@ async function handleRequest(message, context, config, dependencies) {
|
|
|
64
69
|
}
|
|
65
70
|
} catch (err) {
|
|
66
71
|
logger.log('ERROR', `[TaskEngine] Error processing task ${type}`, err);
|
|
67
|
-
// We might want to throw here to trigger Pub/Sub retry, depending on the error nature
|
|
68
|
-
// For now, logging error is sufficient as the sub-handlers perform their own try/catch blocks
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
|