bulltrackers-module 1.0.657 โ 1.0.659
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.
- package/functions/api-v2/routes/popular_investors.js +80 -0
- package/functions/computation-system/data/AvailabilityChecker.js +163 -317
- package/functions/computation-system/data/CachedDataLoader.js +158 -222
- package/functions/computation-system/data/DependencyFetcher.js +201 -406
- package/functions/computation-system/executors/MetaExecutor.js +176 -280
- package/functions/computation-system/executors/StandardExecutor.js +325 -383
- package/functions/computation-system/helpers/computation_dispatcher.js +294 -699
- package/functions/computation-system/helpers/computation_worker.js +3 -2
- package/functions/computation-system/legacy/AvailabilityCheckerOld.js +382 -0
- package/functions/computation-system/legacy/CachedDataLoaderOld.js +357 -0
- package/functions/computation-system/legacy/DependencyFetcherOld.js +478 -0
- package/functions/computation-system/legacy/MetaExecutorold.js +364 -0
- package/functions/computation-system/legacy/StandardExecutorold.js +476 -0
- package/functions/computation-system/legacy/computation_dispatcherold.js +944 -0
- package/functions/computation-system/persistence/ResultCommitter.js +137 -188
- package/functions/computation-system/services/SnapshotService.js +129 -0
- package/functions/computation-system/tools/BuildReporter.js +12 -7
- package/functions/computation-system/utils/data_loader.js +213 -238
- package/package.json +3 -2
- package/functions/computation-system/workflows/bulltrackers_pipeline.yaml +0 -163
- package/functions/computation-system/workflows/data_feeder_pipeline.yaml +0 -115
- package/functions/computation-system/workflows/datafeederpipelineinstructions.md +0 -30
- package/functions/computation-system/workflows/morning_prep_pipeline.yaml +0 -55
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bulltrackers-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.659",
|
|
4
4
|
"description": "Helper Functions for Bulltrackers.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
"p-limit": "^3.1.0",
|
|
46
46
|
"require-all": "^3.0.0",
|
|
47
47
|
"sharedsetup": "latest",
|
|
48
|
-
"zod": "^4.3.5"
|
|
48
|
+
"zod": "^4.3.5",
|
|
49
|
+
"@google-cloud/storage": "^7.18.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"bulltracker-deployer": "file:../bulltracker-deployer"
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
# Cloud Workflows: Precision Cursor-Based Orchestrator with Manual Override
|
|
2
|
-
main:
|
|
3
|
-
params: [input]
|
|
4
|
-
steps:
|
|
5
|
-
- init:
|
|
6
|
-
assign:
|
|
7
|
-
- project: '${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}'
|
|
8
|
-
- passes: ["1", "2", "3", "4", "5"]
|
|
9
|
-
- current_date: '${text.split(time.format(sys.now()), "T")[0]}'
|
|
10
|
-
- date_to_run: '${default(map.get(input, "date"), current_date)}'
|
|
11
|
-
|
|
12
|
-
# --- ๐ NEW: CHECK FOR MANUAL OVERRIDE ---
|
|
13
|
-
- check_manual_override:
|
|
14
|
-
switch:
|
|
15
|
-
- condition: '${map.get(input, "action") == "FORCE_RUN"}'
|
|
16
|
-
next: execute_manual_force_run
|
|
17
|
-
|
|
18
|
-
# --- PHASE 1: EXECUTION (Standard + High Mem Retry) ---
|
|
19
|
-
- run_sequential_passes:
|
|
20
|
-
for:
|
|
21
|
-
value: pass_id
|
|
22
|
-
in: ${passes}
|
|
23
|
-
steps:
|
|
24
|
-
- init_cursor:
|
|
25
|
-
assign:
|
|
26
|
-
- n_cursor: 1
|
|
27
|
-
- pass_complete: false
|
|
28
|
-
|
|
29
|
-
- sequential_date_loop:
|
|
30
|
-
switch:
|
|
31
|
-
- condition: ${not pass_complete}
|
|
32
|
-
steps:
|
|
33
|
-
- call_dispatcher:
|
|
34
|
-
call: http.post
|
|
35
|
-
args:
|
|
36
|
-
url: '${"https://europe-west1-" + project + ".cloudfunctions.net/computation-dispatcher"}'
|
|
37
|
-
body:
|
|
38
|
-
pass: '${pass_id}'
|
|
39
|
-
cursorIndex: '${n_cursor}'
|
|
40
|
-
date: '${date_to_run}'
|
|
41
|
-
action: 'DISPATCH'
|
|
42
|
-
auth: { type: OIDC }
|
|
43
|
-
result: dispatch_res
|
|
44
|
-
|
|
45
|
-
- evaluate_dispatch:
|
|
46
|
-
switch:
|
|
47
|
-
# 1. End of Session
|
|
48
|
-
- condition: '${dispatch_res.body.status == "MOVE_TO_NEXT_PASS"}'
|
|
49
|
-
assign:
|
|
50
|
-
- pass_complete: true
|
|
51
|
-
|
|
52
|
-
# 2. Satiation Check
|
|
53
|
-
- condition: '${dispatch_res.body.status == "CONTINUE_PASS" and dispatch_res.body.remainingDates == 0 and dispatch_res.body.dispatched == 0}'
|
|
54
|
-
steps:
|
|
55
|
-
- log_satiation:
|
|
56
|
-
call: sys.log
|
|
57
|
-
args:
|
|
58
|
-
text: '${"Pass " + pass_id + " - โ
Pass satiated. Starting Verification."}'
|
|
59
|
-
- mark_complete:
|
|
60
|
-
assign:
|
|
61
|
-
- pass_complete: true
|
|
62
|
-
|
|
63
|
-
# 3. Work Dispatched
|
|
64
|
-
- condition: '${dispatch_res.body.dispatched > 0}'
|
|
65
|
-
steps:
|
|
66
|
-
- wait_for_completion:
|
|
67
|
-
call: sys.sleep
|
|
68
|
-
args:
|
|
69
|
-
seconds: '${int(dispatch_res.body.etaSeconds)}'
|
|
70
|
-
- update_cursor:
|
|
71
|
-
assign:
|
|
72
|
-
- n_cursor: '${default(dispatch_res.body.nextCursor, n_cursor + 1)}'
|
|
73
|
-
- next_loop_work:
|
|
74
|
-
next: sequential_date_loop
|
|
75
|
-
|
|
76
|
-
# 4. No Work (Fast-Forward)
|
|
77
|
-
- condition: '${dispatch_res.body.dispatched == 0}'
|
|
78
|
-
steps:
|
|
79
|
-
- wait_short:
|
|
80
|
-
call: sys.sleep
|
|
81
|
-
args:
|
|
82
|
-
seconds: 2
|
|
83
|
-
- update_cursor_retry:
|
|
84
|
-
assign:
|
|
85
|
-
- n_cursor: '${default(dispatch_res.body.nextCursor, n_cursor + 1)}'
|
|
86
|
-
- next_loop_retry:
|
|
87
|
-
next: sequential_date_loop
|
|
88
|
-
|
|
89
|
-
# --- VERIFICATION & SWEEP (CRITICAL LOGIC PRESERVED) ---
|
|
90
|
-
- verify_pass_completion:
|
|
91
|
-
call: http.post
|
|
92
|
-
args:
|
|
93
|
-
url: '${"https://europe-west1-" + project + ".cloudfunctions.net/computation-dispatcher"}'
|
|
94
|
-
body:
|
|
95
|
-
action: 'VERIFY'
|
|
96
|
-
pass: '${pass_id}'
|
|
97
|
-
date: '${date_to_run}'
|
|
98
|
-
auth: { type: OIDC }
|
|
99
|
-
result: verify_res
|
|
100
|
-
|
|
101
|
-
- process_sweep_tasks:
|
|
102
|
-
for:
|
|
103
|
-
value: sweep_task
|
|
104
|
-
in: '${verify_res.body.missingTasks}'
|
|
105
|
-
steps:
|
|
106
|
-
- log_sweep:
|
|
107
|
-
call: sys.log
|
|
108
|
-
args:
|
|
109
|
-
text: '${"๐งน SWEEP: Disposing " + sweep_task.taskCount + " high-mem tasks for " + sweep_task.date}'
|
|
110
|
-
- dispatch_force_sweep:
|
|
111
|
-
call: http.post
|
|
112
|
-
args:
|
|
113
|
-
url: '${"https://europe-west1-" + project + ".cloudfunctions.net/computation-dispatcher"}'
|
|
114
|
-
body:
|
|
115
|
-
action: 'SWEEP'
|
|
116
|
-
pass: '${pass_id}'
|
|
117
|
-
date: '${sweep_task.date}'
|
|
118
|
-
auth: { type: OIDC }
|
|
119
|
-
- wait_sweep_completion:
|
|
120
|
-
call: sys.sleep
|
|
121
|
-
args:
|
|
122
|
-
seconds: '${int(sweep_task.eta)}'
|
|
123
|
-
|
|
124
|
-
# --- PHASE 2: FINAL FORENSIC REPORTING ---
|
|
125
|
-
- run_final_forensics:
|
|
126
|
-
for:
|
|
127
|
-
value: pass_id
|
|
128
|
-
in: ${passes}
|
|
129
|
-
steps:
|
|
130
|
-
- generate_final_report:
|
|
131
|
-
call: http.post
|
|
132
|
-
args:
|
|
133
|
-
url: '${"https://europe-west1-" + project + ".cloudfunctions.net/computation-dispatcher"}'
|
|
134
|
-
body:
|
|
135
|
-
action: 'REPORT'
|
|
136
|
-
pass: '${pass_id}'
|
|
137
|
-
date: '${date_to_run}'
|
|
138
|
-
auth: { type: OIDC }
|
|
139
|
-
result: report_res
|
|
140
|
-
|
|
141
|
-
- log_forensics:
|
|
142
|
-
call: sys.log
|
|
143
|
-
args:
|
|
144
|
-
text: '${"๐ FINAL REPORT: Pass " + pass_id + " -> " + report_res.body.issuesFound + " detailed forensic documents created."}'
|
|
145
|
-
|
|
146
|
-
- finish_standard:
|
|
147
|
-
return: "Pipeline Complete with Forensic Analysis"
|
|
148
|
-
|
|
149
|
-
# --- ๐จ MANUAL OVERRIDE EXECUTION PATH ---
|
|
150
|
-
- execute_manual_force_run:
|
|
151
|
-
call: http.post
|
|
152
|
-
args:
|
|
153
|
-
url: '${"https://europe-west1-" + project + ".cloudfunctions.net/computation-dispatcher"}'
|
|
154
|
-
body:
|
|
155
|
-
action: 'FORCE_RUN'
|
|
156
|
-
computation: '${input.computation}'
|
|
157
|
-
date: '${map.get(input, "date")}' # Can be null for ALL_DATES
|
|
158
|
-
resources: '${map.get(input, "resources")}'
|
|
159
|
-
auth: { type: OIDC }
|
|
160
|
-
result: force_res
|
|
161
|
-
|
|
162
|
-
- finish_manual:
|
|
163
|
-
return: '${force_res.body}'
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# Data Feeder Pipeline (V4.0 - Lean Market Close)
|
|
2
|
-
# Schedule: 22:00 UTC
|
|
3
|
-
# Objective: Capture Market Close data & perform Global Indexing at midnight.
|
|
4
|
-
|
|
5
|
-
main:
|
|
6
|
-
params: [input]
|
|
7
|
-
steps:
|
|
8
|
-
- init:
|
|
9
|
-
assign:
|
|
10
|
-
- project: '${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}'
|
|
11
|
-
- location: "europe-west1"
|
|
12
|
-
|
|
13
|
-
# ==========================================
|
|
14
|
-
# TEST MODE ROUTING (Preserved for Debugging)
|
|
15
|
-
# ==========================================
|
|
16
|
-
- check_test_mode:
|
|
17
|
-
switch:
|
|
18
|
-
- condition: '${input != null and "target_step" in input}'
|
|
19
|
-
steps:
|
|
20
|
-
- route_test:
|
|
21
|
-
switch:
|
|
22
|
-
- condition: '${input.target_step == "test_price"}'
|
|
23
|
-
steps:
|
|
24
|
-
- call_price_iso:
|
|
25
|
-
call: http.post
|
|
26
|
-
args:
|
|
27
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/price-fetcher"}'
|
|
28
|
-
auth: { type: OIDC }
|
|
29
|
-
timeout: 300
|
|
30
|
-
- return_price:
|
|
31
|
-
return: "Test Complete: Price Fetcher executed."
|
|
32
|
-
|
|
33
|
-
- condition: '${input.target_step == "test_insights"}'
|
|
34
|
-
steps:
|
|
35
|
-
- call_insights_iso:
|
|
36
|
-
call: http.post
|
|
37
|
-
args:
|
|
38
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/insights-fetcher"}'
|
|
39
|
-
auth: { type: OIDC }
|
|
40
|
-
timeout: 300
|
|
41
|
-
- return_insights:
|
|
42
|
-
return: "Test Complete: Insights Fetcher executed."
|
|
43
|
-
|
|
44
|
-
- condition: '${input.target_step == "test_indexer"}'
|
|
45
|
-
steps:
|
|
46
|
-
- call_indexer_iso:
|
|
47
|
-
call: http.post
|
|
48
|
-
args:
|
|
49
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
|
|
50
|
-
auth: { type: OIDC }
|
|
51
|
-
timeout: 300
|
|
52
|
-
- return_indexer:
|
|
53
|
-
return: "Test Complete: Root Data Indexer executed."
|
|
54
|
-
|
|
55
|
-
# ==========================================
|
|
56
|
-
# PHASE 1: MARKET CLOSE (Starts 22:00 UTC)
|
|
57
|
-
# ==========================================
|
|
58
|
-
|
|
59
|
-
# 1. Price Fetcher
|
|
60
|
-
- phase_2200_price:
|
|
61
|
-
try:
|
|
62
|
-
call: http.post
|
|
63
|
-
args:
|
|
64
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/price-fetcher"}'
|
|
65
|
-
auth: { type: OIDC }
|
|
66
|
-
timeout: 300
|
|
67
|
-
except:
|
|
68
|
-
as: e
|
|
69
|
-
steps:
|
|
70
|
-
- log_price_error:
|
|
71
|
-
call: sys.log
|
|
72
|
-
args: { severity: "WARNING", text: "Price fetch timed out/failed. Proceeding." }
|
|
73
|
-
|
|
74
|
-
# 2. Insights Fetcher (Can run immediately after or parallel)
|
|
75
|
-
- phase_2200_insights:
|
|
76
|
-
try:
|
|
77
|
-
call: http.post
|
|
78
|
-
args:
|
|
79
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/insights-fetcher"}'
|
|
80
|
-
auth: { type: OIDC }
|
|
81
|
-
timeout: 300
|
|
82
|
-
except:
|
|
83
|
-
as: e
|
|
84
|
-
steps:
|
|
85
|
-
- log_insights_error:
|
|
86
|
-
call: sys.log
|
|
87
|
-
args: { severity: "WARNING", text: "Insights fetch timed out/failed. Proceeding." }
|
|
88
|
-
|
|
89
|
-
# ==========================================
|
|
90
|
-
# PHASE 2: WAIT FOR MIDNIGHT (Indexing)
|
|
91
|
-
# ==========================================
|
|
92
|
-
|
|
93
|
-
- align_to_midnight:
|
|
94
|
-
assign:
|
|
95
|
-
- now_sec: '${int(sys.now())}'
|
|
96
|
-
- day_sec: 86400
|
|
97
|
-
# Calculates seconds remaining until the next 00:00 UTC
|
|
98
|
-
- sleep_midnight: '${day_sec - (now_sec % day_sec)}'
|
|
99
|
-
|
|
100
|
-
- wait_for_midnight:
|
|
101
|
-
call: sys.sleep
|
|
102
|
-
args: { seconds: '${sleep_midnight}' }
|
|
103
|
-
|
|
104
|
-
# ==========================================
|
|
105
|
-
# PHASE 3: GLOBAL INDEXING (00:00 UTC)
|
|
106
|
-
# ==========================================
|
|
107
|
-
|
|
108
|
-
- global_index_midnight:
|
|
109
|
-
call: http.post
|
|
110
|
-
args:
|
|
111
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/root-data-indexer"}'
|
|
112
|
-
auth: { type: OIDC }
|
|
113
|
-
|
|
114
|
-
- finish:
|
|
115
|
-
return: "Daily Close Cycle Finished (Price, Insights, Indexing)."
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# ๐งช Workflow Testing Guide
|
|
2
|
-
|
|
3
|
-
Below is a quick-reference guide for manually triggering the **Data Feeder Pipeline** using the Google Cloud Console UI.
|
|
4
|
-
|
|
5
|
-
## How to Run a Test
|
|
6
|
-
|
|
7
|
-
1. Navigate to **Workflows** in your GCP Console.
|
|
8
|
-
2. Select `data-feeder-pipeline`.
|
|
9
|
-
3. Click the **Execute** button at the top.
|
|
10
|
-
4. Paste the specific **JSON Input** from the table below into the input box to bypass schedules and target specific phases.
|
|
11
|
-
|
|
12
|
-
### Test Commands
|
|
13
|
-
|
|
14
|
-
Cloud Function,Input JSON to Use
|
|
15
|
-
Price Fetcher,"{"target_step": "test_price"}"
|
|
16
|
-
Insights Fetcher,"{"target_step": "test_insights"}"
|
|
17
|
-
Popular Investors,"{"target_step": "test_rankings"}"
|
|
18
|
-
Social Orchestrator,"{"target_step": "test_social"}"
|
|
19
|
-
Root Indexer,"{"target_step": "test_indexer"}"
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
### ๐ก Testing Notes & Pro-Tips
|
|
24
|
-
|
|
25
|
-
* **Automatic Indexing:** As of V3.2, you will not see explicit "Index" steps in the workflow visualization for Price, Insights, or Rankings. These functions now trigger the `root-data-indexer` automatically upon completion. The only visible index step is the **Global Verification** in the Midnight Phase.
|
|
26
|
-
* **Verification:** To confirm data was indexed during a test:
|
|
27
|
-
* Check the logs of the individual Cloud Functions (`price-fetcher`, etc.).
|
|
28
|
-
* Or, run the **Midnight Phase** test, which ends with the explicit `global_index_midnight` step.
|
|
29
|
-
* **Variable Checking:** After execution, check the **Variables** tab to view `sleep_midnight` calculations to ensure UTC alignment is functioning correctly.
|
|
30
|
-
* **Permissions:** Ensure the executor has `roles/workflows.invoker`.
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Morning Prep Pipeline
|
|
2
|
-
# Schedule: 04:00 UTC
|
|
3
|
-
# Objective: Refresh Rankings -> Trigger Daily Update (Task Engine)
|
|
4
|
-
|
|
5
|
-
main:
|
|
6
|
-
params: [input]
|
|
7
|
-
steps:
|
|
8
|
-
- init:
|
|
9
|
-
assign:
|
|
10
|
-
- project: '${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}'
|
|
11
|
-
- location: "europe-west1"
|
|
12
|
-
# Define the Task Engine workflow ID to trigger later
|
|
13
|
-
- task_engine_workflow_id: "daily-update-pipeline"
|
|
14
|
-
|
|
15
|
-
# ==========================================
|
|
16
|
-
# STEP 1: REFRESH RANKINGS (The Master List)
|
|
17
|
-
# ==========================================
|
|
18
|
-
- fetch_rankings:
|
|
19
|
-
try:
|
|
20
|
-
call: http.post
|
|
21
|
-
args:
|
|
22
|
-
url: '${"https://" + location + "-" + project + ".cloudfunctions.net/fetch-popular-investors"}'
|
|
23
|
-
auth: { type: OIDC }
|
|
24
|
-
timeout: 540
|
|
25
|
-
except:
|
|
26
|
-
as: e
|
|
27
|
-
steps:
|
|
28
|
-
- log_rankings_fail:
|
|
29
|
-
call: sys.log
|
|
30
|
-
args: { severity: "ERROR", text: "Rankings Fetch Failed. Stopping pipeline to prevent stale Task Engine run." }
|
|
31
|
-
- raise_error:
|
|
32
|
-
raise: ${e}
|
|
33
|
-
|
|
34
|
-
# ==========================================
|
|
35
|
-
# STEP 2: TRIGGER TASK ENGINE
|
|
36
|
-
# ==========================================
|
|
37
|
-
# We trigger the workflow execution directly.
|
|
38
|
-
# This replaces the need for a separate 05:00 UTC Scheduler.
|
|
39
|
-
|
|
40
|
-
- trigger_daily_update:
|
|
41
|
-
call: googleapis.workflowexecutions.v1.projects.locations.workflows.executions.create
|
|
42
|
-
args:
|
|
43
|
-
parent: '${"projects/" + project + "/locations/" + location + "/workflows/" + task_engine_workflow_id}'
|
|
44
|
-
body:
|
|
45
|
-
# Pass explicit arguments to the Task Engine
|
|
46
|
-
argument: '{"userTypes": ["normal", "speculator"], "source": "morning_prep_trigger"}'
|
|
47
|
-
result: execution_result
|
|
48
|
-
|
|
49
|
-
- log_trigger:
|
|
50
|
-
call: sys.log
|
|
51
|
-
args:
|
|
52
|
-
text: '${"โ
Rankings Complete. Triggered Task Engine: " + execution_result.name}'
|
|
53
|
-
|
|
54
|
-
- finish:
|
|
55
|
-
return: "Morning Prep Complete. Task Engine launched."
|