@hotmeshio/hotmesh 0.7.0 → 0.9.0
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/.claude/settings.local.json +8 -0
- package/README.md +158 -38
- package/build/index.d.ts +1 -3
- package/build/index.js +1 -5
- package/build/modules/utils.js +3 -31
- package/build/package.json +63 -79
- package/build/services/activities/activity.d.ts +97 -9
- package/build/services/activities/activity.js +323 -86
- package/build/services/activities/await.d.ts +101 -0
- package/build/services/activities/await.js +103 -2
- package/build/services/activities/cycle.d.ts +82 -0
- package/build/services/activities/cycle.js +86 -8
- package/build/services/activities/hook.d.ts +144 -1
- package/build/services/activities/hook.js +162 -21
- package/build/services/activities/interrupt.d.ts +112 -0
- package/build/services/activities/interrupt.js +134 -29
- package/build/services/activities/signal.d.ts +111 -4
- package/build/services/activities/signal.js +136 -28
- package/build/services/activities/trigger.d.ts +56 -4
- package/build/services/activities/trigger.js +119 -35
- package/build/services/activities/worker.d.ts +107 -0
- package/build/services/activities/worker.js +109 -2
- package/build/services/collator/index.d.ts +116 -30
- package/build/services/collator/index.js +211 -115
- package/build/services/connector/factory.d.ts +1 -1
- package/build/services/connector/factory.js +1 -11
- package/build/services/engine/index.d.ts +22 -6
- package/build/services/engine/index.js +49 -18
- package/build/services/exporter/index.d.ts +2 -0
- package/build/services/exporter/index.js +1 -0
- package/build/services/hotmesh/index.d.ts +471 -236
- package/build/services/hotmesh/index.js +473 -238
- package/build/services/memflow/client.js +2 -2
- package/build/services/memflow/handle.js +1 -1
- package/build/services/memflow/index.d.ts +1 -1
- package/build/services/memflow/index.js +1 -1
- package/build/services/memflow/workflow/all.d.ts +28 -3
- package/build/services/memflow/workflow/all.js +28 -3
- package/build/services/memflow/workflow/context.d.ts +44 -1
- package/build/services/memflow/workflow/context.js +44 -1
- package/build/services/memflow/workflow/didRun.d.ts +23 -3
- package/build/services/memflow/workflow/didRun.js +23 -3
- package/build/services/memflow/workflow/emit.d.ts +43 -4
- package/build/services/memflow/workflow/emit.js +43 -4
- package/build/services/memflow/workflow/enrich.d.ts +32 -4
- package/build/services/memflow/workflow/enrich.js +32 -4
- package/build/services/memflow/workflow/entityMethods.d.ts +54 -7
- package/build/services/memflow/workflow/entityMethods.js +54 -7
- package/build/services/memflow/workflow/execChild.d.ts +96 -8
- package/build/services/memflow/workflow/execChild.js +96 -8
- package/build/services/memflow/workflow/execHook.d.ts +54 -39
- package/build/services/memflow/workflow/execHook.js +52 -38
- package/build/services/memflow/workflow/execHookBatch.d.ts +82 -29
- package/build/services/memflow/workflow/execHookBatch.js +80 -28
- package/build/services/memflow/workflow/hook.d.ts +68 -3
- package/build/services/memflow/workflow/hook.js +69 -4
- package/build/services/memflow/workflow/index.d.ts +65 -10
- package/build/services/memflow/workflow/index.js +65 -10
- package/build/services/memflow/workflow/interrupt.d.ts +50 -4
- package/build/services/memflow/workflow/interrupt.js +50 -4
- package/build/services/memflow/workflow/interruption.d.ts +49 -16
- package/build/services/memflow/workflow/interruption.js +49 -16
- package/build/services/memflow/workflow/isSideEffectAllowed.d.ts +21 -4
- package/build/services/memflow/workflow/isSideEffectAllowed.js +21 -4
- package/build/services/memflow/workflow/proxyActivities.d.ts +70 -42
- package/build/services/memflow/workflow/proxyActivities.js +70 -42
- package/build/services/memflow/workflow/random.d.ts +33 -3
- package/build/services/memflow/workflow/random.js +33 -3
- package/build/services/memflow/workflow/searchMethods.d.ts +49 -2
- package/build/services/memflow/workflow/searchMethods.js +49 -2
- package/build/services/memflow/workflow/signal.d.ts +51 -22
- package/build/services/memflow/workflow/signal.js +52 -23
- package/build/services/memflow/workflow/sleepFor.d.ts +57 -18
- package/build/services/memflow/workflow/sleepFor.js +57 -18
- package/build/services/memflow/workflow/trace.d.ts +39 -6
- package/build/services/memflow/workflow/trace.js +39 -6
- package/build/services/memflow/workflow/waitFor.d.ts +55 -18
- package/build/services/memflow/workflow/waitFor.js +55 -18
- package/build/services/router/consumption/index.js +1 -1
- package/build/services/search/factory.js +1 -9
- package/build/services/store/factory.js +1 -9
- package/build/services/store/index.d.ts +6 -1
- package/build/services/store/providers/postgres/kvsql.d.ts +4 -0
- package/build/services/store/providers/postgres/kvsql.js +4 -0
- package/build/services/store/providers/postgres/kvtransaction.d.ts +2 -0
- package/build/services/store/providers/postgres/kvtransaction.js +23 -0
- package/build/services/store/providers/postgres/kvtypes/hash/basic.d.ts +51 -0
- package/build/services/store/providers/postgres/kvtypes/hash/basic.js +193 -1
- package/build/services/store/providers/postgres/kvtypes/hash/index.d.ts +4 -0
- package/build/services/store/providers/postgres/kvtypes/hash/index.js +6 -0
- package/build/services/store/providers/postgres/postgres.d.ts +21 -1
- package/build/services/store/providers/postgres/postgres.js +42 -4
- package/build/services/stream/factory.js +1 -17
- package/build/services/stream/providers/postgres/scout.js +2 -2
- package/build/services/sub/factory.js +1 -9
- package/build/services/sub/index.d.ts +1 -1
- package/build/services/sub/providers/postgres/postgres.d.ts +1 -1
- package/build/services/sub/providers/postgres/postgres.js +25 -10
- package/build/services/task/index.d.ts +1 -1
- package/build/services/task/index.js +2 -6
- package/build/services/telemetry/index.js +6 -0
- package/build/types/activity.d.ts +1 -1
- package/build/types/hotmesh.d.ts +1 -1
- package/build/types/index.d.ts +0 -1
- package/build/types/index.js +1 -4
- package/build/types/job.d.ts +1 -1
- package/build/types/memflow.d.ts +1 -1
- package/build/types/provider.d.ts +1 -1
- package/build/types/quorum.d.ts +2 -2
- package/build/vitest.config.d.ts +2 -0
- package/build/vitest.config.js +18 -0
- package/index.ts +0 -4
- package/package.json +63 -79
- package/vitest.config.ts +17 -0
- package/build/services/connector/providers/ioredis.d.ts +0 -9
- package/build/services/connector/providers/ioredis.js +0 -26
- package/build/services/connector/providers/redis.d.ts +0 -9
- package/build/services/connector/providers/redis.js +0 -38
- package/build/services/search/providers/redis/ioredis.d.ts +0 -23
- package/build/services/search/providers/redis/ioredis.js +0 -189
- package/build/services/search/providers/redis/redis.d.ts +0 -23
- package/build/services/search/providers/redis/redis.js +0 -202
- package/build/services/store/providers/redis/_base.d.ts +0 -137
- package/build/services/store/providers/redis/_base.js +0 -980
- package/build/services/store/providers/redis/ioredis.d.ts +0 -20
- package/build/services/store/providers/redis/ioredis.js +0 -190
- package/build/services/store/providers/redis/redis.d.ts +0 -18
- package/build/services/store/providers/redis/redis.js +0 -199
- package/build/services/stream/providers/redis/ioredis.d.ts +0 -61
- package/build/services/stream/providers/redis/ioredis.js +0 -272
- package/build/services/stream/providers/redis/redis.d.ts +0 -61
- package/build/services/stream/providers/redis/redis.js +0 -305
- package/build/services/sub/providers/redis/ioredis.d.ts +0 -20
- package/build/services/sub/providers/redis/ioredis.js +0 -161
- package/build/services/sub/providers/redis/redis.d.ts +0 -18
- package/build/services/sub/providers/redis/redis.js +0 -148
- package/build/types/redis.d.ts +0 -258
- package/build/types/redis.js +0 -11
|
@@ -42,85 +42,158 @@ class CollatorService {
|
|
|
42
42
|
dimensions.push('0');
|
|
43
43
|
return dimensions.join(',');
|
|
44
44
|
}
|
|
45
|
+
// ──────────────────────────────────────────────────
|
|
46
|
+
// Leg1 notarization
|
|
47
|
+
// ──────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Leg1 entry: increment attempt counter (+1T).
|
|
50
|
+
* NOT bundled with Leg1 work — exists only to mark entry.
|
|
51
|
+
*/
|
|
45
52
|
static async notarizeEntry(activity, transaction) {
|
|
46
|
-
|
|
47
|
-
const amount = await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, -100000000000000, this.getDimensionalAddress(activity), transaction);
|
|
53
|
+
const amount = await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, this.WEIGHTS.LEG1_ENTRY, this.getDimensionalAddress(activity), transaction);
|
|
48
54
|
this.verifyInteger(amount, 1, 'enter');
|
|
49
55
|
return amount;
|
|
50
56
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Leg1 completion: increment +100B to mark Leg1 complete.
|
|
59
|
+
* For cycle=true activities, also pre-seeds the Leg2 entry counter (+1)
|
|
60
|
+
* so the first real Leg2 gets adjacentIndex=1 (new dimension).
|
|
61
|
+
* MUST be bundled in the same transaction as Leg1 durable work.
|
|
62
|
+
*/
|
|
63
|
+
static async notarizeLeg1Completion(activity, transaction) {
|
|
64
|
+
const amount = activity.config.cycle
|
|
65
|
+
? this.WEIGHTS.LEG1_COMPLETE + this.WEIGHTS.LEG2_ENTRY
|
|
66
|
+
: this.WEIGHTS.LEG1_COMPLETE;
|
|
67
|
+
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, amount, this.getDimensionalAddress(activity), transaction);
|
|
56
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Leg1 early exit: marks Leg1 complete for activities that
|
|
71
|
+
* only run Leg1 and fully close (e.g., Cycle).
|
|
72
|
+
* Increment +100B (Leg1 completion marker).
|
|
73
|
+
*/
|
|
57
74
|
static async notarizeEarlyExit(activity, transaction) {
|
|
58
|
-
|
|
59
|
-
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, -11000000000000, this.getDimensionalAddress(activity), transaction);
|
|
75
|
+
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, this.WEIGHTS.LEG1_COMPLETE, this.getDimensionalAddress(activity), transaction);
|
|
60
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Leg1 early completion: marks Leg1 complete for Leg1-only
|
|
79
|
+
* activities that spawn children (e.g., Signal, Hook passthrough,
|
|
80
|
+
* Interrupt-another). Increment +100B.
|
|
81
|
+
*/
|
|
61
82
|
static async notarizeEarlyCompletion(activity, transaction) {
|
|
62
|
-
|
|
63
|
-
//3rd digit is optionally kept open if the activity might be used in a cycle
|
|
64
|
-
const decrement = activity.config.cycle
|
|
65
|
-
? 10000000000000
|
|
66
|
-
: 11000000000000;
|
|
67
|
-
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, 1000001 - decrement, this.getDimensionalAddress(activity), transaction);
|
|
83
|
+
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, this.WEIGHTS.LEG1_COMPLETE, this.getDimensionalAddress(activity), transaction);
|
|
68
84
|
}
|
|
85
|
+
// ──────────────────────────────────────────────────
|
|
86
|
+
// Leg2 notarization (entry + 3-step protocol)
|
|
87
|
+
// ──────────────────────────────────────────────────
|
|
69
88
|
/**
|
|
70
|
-
*
|
|
89
|
+
* Leg2 entry: atomically increments the activity ledger (+1) and
|
|
90
|
+
* seeds the GUID ledger with the ordinal IF NOT EXISTS.
|
|
91
|
+
* Returns [activityLedger, guidLedger] after the compound operation.
|
|
71
92
|
*/
|
|
72
|
-
static async
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
93
|
+
static async notarizeLeg2Entry(activity, guid, transaction) {
|
|
94
|
+
const jid = activity.context.metadata.jid;
|
|
95
|
+
const localMulti = transaction || activity.store.transact();
|
|
96
|
+
//compound: increment activity Leg2 counter and seed GUID ledger
|
|
97
|
+
await activity.store.collateLeg2Entry(jid, activity.metadata.aid, guid, this.getDimensionalAddress(activity, true), localMulti);
|
|
98
|
+
const results = await localMulti.exec();
|
|
99
|
+
const result = results[0];
|
|
100
|
+
const [amountConcrete, amountSynthetic] = Array.isArray(result)
|
|
101
|
+
? result
|
|
102
|
+
: [result, result];
|
|
103
|
+
this.verifyInteger(amountConcrete, 2, 'enter');
|
|
104
|
+
this.verifySyntheticInteger(amountSynthetic);
|
|
105
|
+
return [amountConcrete, amountSynthetic];
|
|
76
106
|
}
|
|
77
107
|
/**
|
|
78
|
-
*
|
|
108
|
+
* Step 1: Mark Leg2 work done (+10B on GUID ledger only).
|
|
109
|
+
* MUST be bundled with Leg2 durable work writes.
|
|
79
110
|
*/
|
|
80
|
-
static async
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return amount > 1000000;
|
|
84
|
-
}
|
|
85
|
-
return false;
|
|
111
|
+
static async notarizeStep1(activity, guid, transaction) {
|
|
112
|
+
const jid = activity.context.metadata.jid;
|
|
113
|
+
await activity.store.collateSynthetic(jid, guid, this.WEIGHTS.STEP1_WORK, transaction);
|
|
86
114
|
}
|
|
87
115
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* synthetic key represents different dimensional realities and is used to
|
|
93
|
-
* track re-entry overages (it distinguishes between the original and re-entry).
|
|
94
|
-
* The essential challenge is: is this a re-entry that is purposeful in
|
|
95
|
-
* order to induce cycles, or is the re-entry due to a failure in the system?
|
|
116
|
+
* Step 2: Mark children spawned (+1B on GUID ledger only).
|
|
117
|
+
* The job semaphore update and GUID job-closed snapshot are handled
|
|
118
|
+
* by the compound `setStatusAndCollateGuid` primitive, which MUST
|
|
119
|
+
* be called in the same transaction.
|
|
96
120
|
*/
|
|
97
|
-
static async
|
|
121
|
+
static async notarizeStep2(activity, guid, transaction) {
|
|
98
122
|
const jid = activity.context.metadata.jid;
|
|
99
|
-
|
|
100
|
-
//increment by 1_000_000 (indicates re-entry and is used to drive the 'dimensional address' for adjacent activities (minus 1))
|
|
101
|
-
await activity.store.collate(jid, activity.metadata.aid, 1000000, this.getDimensionalAddress(activity, true), localMulti);
|
|
102
|
-
await activity.store.collateSynthetic(jid, guid, 1000000, localMulti);
|
|
103
|
-
const [_amountConcrete, _amountSynthetic] = await localMulti.exec();
|
|
104
|
-
const amountConcrete = Array.isArray(_amountConcrete)
|
|
105
|
-
? _amountConcrete[1]
|
|
106
|
-
: _amountConcrete;
|
|
107
|
-
const amountSynthetic = Array.isArray(_amountSynthetic)
|
|
108
|
-
? _amountSynthetic[1]
|
|
109
|
-
: _amountSynthetic;
|
|
110
|
-
this.verifyInteger(amountConcrete, 2, 'enter');
|
|
111
|
-
this.verifySyntheticInteger(amountSynthetic);
|
|
112
|
-
return amountConcrete;
|
|
123
|
+
await activity.store.collateSynthetic(jid, guid, this.WEIGHTS.STEP2_SPAWN, transaction);
|
|
113
124
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Step 3: Mark job completion tasks done (+100M on GUID ledger only).
|
|
127
|
+
* MUST be bundled with job completion durable writes.
|
|
128
|
+
*/
|
|
129
|
+
static async notarizeStep3(activity, guid, transaction) {
|
|
130
|
+
const jid = activity.context.metadata.jid;
|
|
131
|
+
await activity.store.collateSynthetic(jid, guid, this.WEIGHTS.STEP3_CLEANUP, transaction);
|
|
117
132
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Finalize: close the activity to new Leg2 GUIDs (+200T).
|
|
135
|
+
* Sets pos 1 to 2 (finalized).
|
|
136
|
+
* Only for non-cycle activities after final SUCCESS/ERROR.
|
|
137
|
+
*/
|
|
138
|
+
static async notarizeFinalize(activity, transaction) {
|
|
139
|
+
if (!activity.config.cycle) {
|
|
140
|
+
await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, this.WEIGHTS.FINALIZE, this.getDimensionalAddress(activity), transaction);
|
|
141
|
+
}
|
|
123
142
|
}
|
|
143
|
+
// ──────────────────────────────────────────────────
|
|
144
|
+
// GUID ledger extraction (step-level resume)
|
|
145
|
+
// ──────────────────────────────────────────────────
|
|
146
|
+
/**
|
|
147
|
+
* Check if Step 1 (work done) is complete on the GUID ledger.
|
|
148
|
+
* Position 5 (10B digit) > 0.
|
|
149
|
+
*/
|
|
150
|
+
static isGuidStep1Done(guidLedger) {
|
|
151
|
+
return this.getDigitAtPosition(guidLedger, 5) > 0;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Check if Step 2 (children spawned) is complete on the GUID ledger.
|
|
155
|
+
* Position 6 (1B digit) > 0.
|
|
156
|
+
*/
|
|
157
|
+
static isGuidStep2Done(guidLedger) {
|
|
158
|
+
return this.getDigitAtPosition(guidLedger, 6) > 0;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check if Step 3 (job completion tasks) is complete on the GUID ledger.
|
|
162
|
+
* Position 7 (100M digit) > 0.
|
|
163
|
+
*/
|
|
164
|
+
static isGuidStep3Done(guidLedger) {
|
|
165
|
+
return this.getDigitAtPosition(guidLedger, 7) > 0;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if this GUID was responsible for closing the job.
|
|
169
|
+
* Position 4 (100B digit) > 0 (job closed snapshot).
|
|
170
|
+
*/
|
|
171
|
+
static isGuidJobClosed(guidLedger) {
|
|
172
|
+
return this.getDigitAtPosition(guidLedger, 4) > 0;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get the attempt count from the GUID ledger (last 8 digits).
|
|
176
|
+
*/
|
|
177
|
+
static getGuidAttemptCount(guidLedger) {
|
|
178
|
+
return guidLedger % 100000000;
|
|
179
|
+
}
|
|
180
|
+
// ──────────────────────────────────────────────────
|
|
181
|
+
// Digit extraction
|
|
182
|
+
// ──────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Gets the digit at a 1-indexed position from a 15-digit ledger value.
|
|
185
|
+
* The value is left-padded to 15 digits before extraction.
|
|
186
|
+
*/
|
|
187
|
+
static getDigitAtPosition(num, position) {
|
|
188
|
+
const numStr = num.toString().padStart(this.targetLength, '0');
|
|
189
|
+
if (position < 1 || position > this.targetLength) {
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
return parseInt(numStr[position - 1], 10);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* @deprecated Use getDigitAtPosition (1-indexed) instead
|
|
196
|
+
*/
|
|
124
197
|
static getDigitAtIndex(num, targetDigitIndex) {
|
|
125
198
|
const numStr = num.toString();
|
|
126
199
|
if (targetDigitIndex < 0 || targetDigitIndex >= numStr.length) {
|
|
@@ -129,77 +202,79 @@ class CollatorService {
|
|
|
129
202
|
const digit = parseInt(numStr[targetDigitIndex], 10);
|
|
130
203
|
return digit;
|
|
131
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Extracts the dimensional index from the Leg2 entry counter.
|
|
207
|
+
* Non-cycle activities: first Leg2 → leg2Count=1 → 1-1=0 (same dimension as Leg1).
|
|
208
|
+
* Cycle activities: first Leg2 → leg2Count=2 (pre-seeded +1) → 2-1=1 (new dimension).
|
|
209
|
+
*/
|
|
132
210
|
static getDimensionalIndex(num) {
|
|
133
|
-
const
|
|
134
|
-
if (
|
|
211
|
+
const leg2EntryCount = num % 100000000;
|
|
212
|
+
if (leg2EntryCount <= 0) {
|
|
135
213
|
return null;
|
|
136
214
|
}
|
|
137
|
-
|
|
138
|
-
const extractedInt = parseInt(extractedStr, 10);
|
|
139
|
-
return extractedInt - 1;
|
|
140
|
-
}
|
|
141
|
-
static isDuplicate(num, targetDigitIndex) {
|
|
142
|
-
return this.getDigitAtIndex(num, targetDigitIndex) < 8;
|
|
143
|
-
}
|
|
144
|
-
static isInactive(num) {
|
|
145
|
-
return this.getDigitAtIndex(num, 2) < 9;
|
|
146
|
-
}
|
|
147
|
-
static isPrimed(amount, leg) {
|
|
148
|
-
//activity entry is not allowed if paths not properly pre-set
|
|
149
|
-
if (leg == 1) {
|
|
150
|
-
return amount != -100000000000000;
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
return (this.getDigitAtIndex(amount, 0) < 9 &&
|
|
154
|
-
this.getDigitAtIndex(amount, 1) < 9);
|
|
155
|
-
}
|
|
215
|
+
return leg2EntryCount - 1;
|
|
156
216
|
}
|
|
217
|
+
// ──────────────────────────────────────────────────
|
|
218
|
+
// Verification
|
|
219
|
+
// ──────────────────────────────────────────────────
|
|
157
220
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
221
|
+
* Verifies the GUID ledger value for step-level resume decisions.
|
|
222
|
+
* The GUID ledger is seeded with an ordinal position (last 8 digits)
|
|
223
|
+
* on first entry; step markers drive all resume/reject logic.
|
|
224
|
+
*
|
|
225
|
+
* Fully processed: Step 3 done, or Steps 1+2 done without job closure.
|
|
226
|
+
* Crash recovery: Any incomplete step combination is allowed for resume.
|
|
164
227
|
*/
|
|
165
228
|
static verifySyntheticInteger(amount) {
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
229
|
+
const step2Done = this.isGuidStep2Done(amount);
|
|
230
|
+
const step3Done = this.isGuidStep3Done(amount);
|
|
231
|
+
const jobClosed = this.isGuidJobClosed(amount);
|
|
232
|
+
if (step3Done) {
|
|
233
|
+
//all steps complete; nothing more to do
|
|
170
234
|
throw new errors_1.CollationError(amount, 2, 'enter', collator_1.CollationFaultType.INACTIVE);
|
|
171
235
|
}
|
|
172
|
-
|
|
173
|
-
//
|
|
174
|
-
throw new errors_1.CollationError(amount, 2, 'enter', collator_1.CollationFaultType.
|
|
236
|
+
if (step2Done && !jobClosed) {
|
|
237
|
+
//steps 1+2 done but this GUID didn't close the job; no Step 3 needed
|
|
238
|
+
throw new errors_1.CollationError(amount, 2, 'enter', collator_1.CollationFaultType.INACTIVE);
|
|
175
239
|
}
|
|
240
|
+
//all other cases: allow entry
|
|
241
|
+
// - no steps done (fresh entry or pre-step-1 crash recovery)
|
|
242
|
+
// - step 1 done, step 2 not (crash after step 1)
|
|
243
|
+
// - steps 1+2 done, job closed, step 3 not (crash recovery for step 3)
|
|
176
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Verifies the activity ledger value at entry boundaries.
|
|
247
|
+
*
|
|
248
|
+
* Leg1 enter: pos 3 (1T digit) must be > 0 after +1T (proves seed exists).
|
|
249
|
+
* pos 4 (100B) must be 0 (Leg1 not yet complete).
|
|
250
|
+
* If pos 3 > 1 and pos 4 == 1, it's a stale/replayed message.
|
|
251
|
+
*
|
|
252
|
+
* Leg2 enter: pos 4 (100B) must be > 0 (Leg1 complete, reentry authorized).
|
|
253
|
+
* pos 1 (100T) must be < 2 (not finalized) — cycle activities exempt.
|
|
254
|
+
*/
|
|
177
255
|
static verifyInteger(amount, leg, stage) {
|
|
178
256
|
let faultType;
|
|
179
257
|
if (leg === 1 && stage === 'enter') {
|
|
180
|
-
|
|
258
|
+
const leg1Attempts = this.getDigitAtPosition(amount, 3);
|
|
259
|
+
const leg1Complete = this.getDigitAtPosition(amount, 4);
|
|
260
|
+
if (leg1Attempts === 0) {
|
|
261
|
+
//seed was not set (no authorization)
|
|
181
262
|
faultType = collator_1.CollationFaultType.MISSING;
|
|
182
263
|
}
|
|
183
|
-
else if (
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
else if (amount != 899000000000000) {
|
|
187
|
-
faultType = collator_1.CollationFaultType.INVALID;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
else if (leg === 1 && stage === 'exit') {
|
|
191
|
-
if (amount === -10000000000000) {
|
|
192
|
-
faultType = collator_1.CollationFaultType.MISSING;
|
|
193
|
-
}
|
|
194
|
-
else if (this.isDuplicate(amount, 1)) {
|
|
264
|
+
else if (leg1Complete > 0) {
|
|
265
|
+
//Leg1 already completed — stale/replayed message
|
|
195
266
|
faultType = collator_1.CollationFaultType.DUPLICATE;
|
|
196
267
|
}
|
|
197
268
|
}
|
|
198
269
|
else if (leg === 2 && stage === 'enter') {
|
|
199
|
-
|
|
270
|
+
const leg1Complete = this.getDigitAtPosition(amount, 4);
|
|
271
|
+
const finalized = this.getDigitAtPosition(amount, 1);
|
|
272
|
+
if (leg1Complete === 0) {
|
|
273
|
+
//Leg1 not complete — reentry not authorized
|
|
200
274
|
faultType = collator_1.CollationFaultType.FORBIDDEN;
|
|
201
275
|
}
|
|
202
|
-
else if (
|
|
276
|
+
else if (finalized >= 2) {
|
|
277
|
+
//activity finalized (pos 1 = 2) — no new Leg2 GUIDs accepted
|
|
203
278
|
faultType = collator_1.CollationFaultType.INACTIVE;
|
|
204
279
|
}
|
|
205
280
|
}
|
|
@@ -207,6 +282,9 @@ class CollatorService {
|
|
|
207
282
|
throw new errors_1.CollationError(amount, leg, stage, faultType);
|
|
208
283
|
}
|
|
209
284
|
}
|
|
285
|
+
// ──────────────────────────────────────────────────
|
|
286
|
+
// Dimensional address resolution
|
|
287
|
+
// ──────────────────────────────────────────────────
|
|
210
288
|
static getDimensionsById(ancestors, dad) {
|
|
211
289
|
//ancestors is an ordered list of all ancestors, starting with the trigger (['t1', 'a1', 'a2'])
|
|
212
290
|
//dad is the dimensional address of the ancestors list (',0,5,3')
|
|
@@ -221,18 +299,19 @@ class CollatorService {
|
|
|
221
299
|
});
|
|
222
300
|
return map;
|
|
223
301
|
}
|
|
302
|
+
// ──────────────────────────────────────────────────
|
|
303
|
+
// Seeds
|
|
304
|
+
// ──────────────────────────────────────────────────
|
|
224
305
|
/**
|
|
225
|
-
* All
|
|
226
|
-
|
|
227
|
-
static getSeed() {
|
|
228
|
-
return '999000000000000';
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* All trigger activities are assigned a status seed in a completed state
|
|
306
|
+
* All trigger activities are assigned a status seed in a completed state.
|
|
307
|
+
* Seed: 101100000000001 (authorized, 1 Leg1 entry, Leg1 complete, 1 Leg2 entry)
|
|
232
308
|
*/
|
|
233
309
|
static getTriggerSeed() {
|
|
234
|
-
return '
|
|
310
|
+
return '101100000000001';
|
|
235
311
|
}
|
|
312
|
+
// ──────────────────────────────────────────────────
|
|
313
|
+
// Compiler
|
|
314
|
+
// ──────────────────────────────────────────────────
|
|
236
315
|
/**
|
|
237
316
|
* entry point for compiler-type activities. This is called by the compiler
|
|
238
317
|
* to bind the sorted activity IDs to the trigger activity. These are then used
|
|
@@ -291,3 +370,20 @@ class CollatorService {
|
|
|
291
370
|
exports.CollatorService = CollatorService;
|
|
292
371
|
//max int digit count that supports `hincrby`
|
|
293
372
|
CollatorService.targetLength = 15;
|
|
373
|
+
/**
|
|
374
|
+
* Positional weights for the 15-digit activity/GUID ledger.
|
|
375
|
+
*
|
|
376
|
+
* Position: 1 2 3 4 5 6 7 8-15
|
|
377
|
+
* Weight: 100T 10T 1T 100B 10B 1B 100M 10M..1
|
|
378
|
+
*/
|
|
379
|
+
CollatorService.WEIGHTS = {
|
|
380
|
+
AUTH: 100000000000000,
|
|
381
|
+
FINALIZE: 200000000000000,
|
|
382
|
+
LEG1_ENTRY: 1000000000000,
|
|
383
|
+
LEG1_COMPLETE: 100000000000,
|
|
384
|
+
STEP1_WORK: 10000000000,
|
|
385
|
+
STEP2_SPAWN: 1000000000,
|
|
386
|
+
STEP3_CLEANUP: 100000000,
|
|
387
|
+
LEG2_ENTRY: 1,
|
|
388
|
+
GUID_SNAPSHOT: 100000000000, // 100B on GUID ledger (job closed snapshot)
|
|
389
|
+
};
|
|
@@ -3,7 +3,7 @@ import { ProviderConfig, ProviderNativeClient } from '../../types/provider';
|
|
|
3
3
|
export declare class ConnectorService {
|
|
4
4
|
static disconnectAll(): Promise<void>;
|
|
5
5
|
/**
|
|
6
|
-
* Connect to a provider (
|
|
6
|
+
* Connect to a provider (nats, postgres) and return the native
|
|
7
7
|
* client. Connections are handled by the engine and worker routers at
|
|
8
8
|
* initialization, but the factory method provided here is useful
|
|
9
9
|
* for testing provider configurations.
|
|
@@ -2,19 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConnectorService = void 0;
|
|
4
4
|
const utils_1 = require("../../modules/utils");
|
|
5
|
-
const ioredis_1 = require("./providers/ioredis");
|
|
6
5
|
const nats_1 = require("./providers/nats");
|
|
7
6
|
const postgres_1 = require("./providers/postgres");
|
|
8
|
-
const redis_1 = require("./providers/redis");
|
|
9
7
|
class ConnectorService {
|
|
10
8
|
static async disconnectAll() {
|
|
11
|
-
await redis_1.RedisConnection.disconnectAll();
|
|
12
|
-
await ioredis_1.RedisConnection.disconnectAll();
|
|
13
9
|
await postgres_1.PostgresConnection.disconnectAll();
|
|
14
10
|
await nats_1.NatsConnection.disconnectAll();
|
|
15
11
|
}
|
|
16
12
|
/**
|
|
17
|
-
* Connect to a provider (
|
|
13
|
+
* Connect to a provider (nats, postgres) and return the native
|
|
18
14
|
* client. Connections are handled by the engine and worker routers at
|
|
19
15
|
* initialization, but the factory method provided here is useful
|
|
20
16
|
* for testing provider configurations.
|
|
@@ -81,12 +77,6 @@ class ConnectorService {
|
|
|
81
77
|
let clientInstance;
|
|
82
78
|
const id = (0, utils_1.guid)();
|
|
83
79
|
switch (providerType) {
|
|
84
|
-
case 'redis':
|
|
85
|
-
clientInstance = await redis_1.RedisConnection.connect(id, providerClass, options, { provider: providerName });
|
|
86
|
-
break;
|
|
87
|
-
case 'ioredis':
|
|
88
|
-
clientInstance = await ioredis_1.RedisConnection.connect(id, providerClass, options, { provider: providerName });
|
|
89
|
-
break;
|
|
90
80
|
case 'nats':
|
|
91
81
|
clientInstance = await nats_1.NatsConnection.connect(id, providerClass, options, { provider: providerName });
|
|
92
82
|
break;
|
|
@@ -31,11 +31,17 @@ declare class EngineService {
|
|
|
31
31
|
appId: string;
|
|
32
32
|
guid: string;
|
|
33
33
|
exporter: ExporterService | null;
|
|
34
|
+
/** @hidden */
|
|
34
35
|
search: SearchService<ProviderClient> | null;
|
|
36
|
+
/** @hidden */
|
|
35
37
|
store: StoreService<ProviderClient, ProviderTransaction> | null;
|
|
38
|
+
/** @hidden */
|
|
36
39
|
stream: StreamService<ProviderClient, ProviderTransaction> | null;
|
|
40
|
+
/** @hidden */
|
|
37
41
|
subscribe: SubService<ProviderClient> | null;
|
|
42
|
+
/** @hidden */
|
|
38
43
|
router: Router<typeof this.stream> | null;
|
|
44
|
+
/** @hidden */
|
|
39
45
|
taskService: TaskService | null;
|
|
40
46
|
logger: ILogger;
|
|
41
47
|
cacheMode: CacheMode;
|
|
@@ -143,7 +149,7 @@ declare class EngineService {
|
|
|
143
149
|
/**
|
|
144
150
|
* @private
|
|
145
151
|
*/
|
|
146
|
-
execAdjacentParent(context: JobState, jobOutput: JobOutput, emit?: boolean): Promise<string>;
|
|
152
|
+
execAdjacentParent(context: JobState, jobOutput: JobOutput, emit?: boolean, transaction?: ProviderTransaction): Promise<string>;
|
|
147
153
|
/**
|
|
148
154
|
* @private
|
|
149
155
|
*/
|
|
@@ -161,17 +167,27 @@ declare class EngineService {
|
|
|
161
167
|
*/
|
|
162
168
|
scrub(jobId: string): Promise<void>;
|
|
163
169
|
/**
|
|
170
|
+
* Delivers a signal (data payload) to a paused hook activity,
|
|
171
|
+
* resuming its Leg 2 execution. The `topic` must match a hook rule
|
|
172
|
+
* defined in the YAML graph's `hooks` section. The engine locates
|
|
173
|
+
* the target activity and dimension for reentry based on the hook
|
|
174
|
+
* rule's match conditions.
|
|
175
|
+
*
|
|
164
176
|
* @private
|
|
165
177
|
*/
|
|
166
|
-
|
|
178
|
+
signal(topic: string, data: JobData, status?: StreamStatus, code?: StreamCode, transaction?: ProviderTransaction): Promise<string>;
|
|
167
179
|
/**
|
|
168
180
|
* @private
|
|
169
181
|
*/
|
|
170
182
|
hookTime(jobId: string, gId: string, topicOrActivity: string, type?: WorkListTaskType): Promise<string | void>;
|
|
171
183
|
/**
|
|
184
|
+
* Fan-out variant of `signal()` that delivers data to **all**
|
|
185
|
+
* paused workflows matching a search query. Useful for resuming
|
|
186
|
+
* a batch of workflows waiting on the same external event.
|
|
187
|
+
*
|
|
172
188
|
* @private
|
|
173
189
|
*/
|
|
174
|
-
|
|
190
|
+
signalAll(hookTopic: string, data: JobData, keyResolver: JobStatsInput, queryFacets?: string[]): Promise<string[]>;
|
|
175
191
|
/**
|
|
176
192
|
* @private
|
|
177
193
|
*/
|
|
@@ -199,7 +215,7 @@ declare class EngineService {
|
|
|
199
215
|
/**
|
|
200
216
|
* @private
|
|
201
217
|
*/
|
|
202
|
-
pubOneTimeSubs(context: JobState, jobOutput: JobOutput, emit?: boolean): Promise<void>;
|
|
218
|
+
pubOneTimeSubs(context: JobState, jobOutput: JobOutput, emit?: boolean, transaction?: ProviderTransaction): Promise<void>;
|
|
203
219
|
/**
|
|
204
220
|
* @private
|
|
205
221
|
*/
|
|
@@ -207,7 +223,7 @@ declare class EngineService {
|
|
|
207
223
|
/**
|
|
208
224
|
* @private
|
|
209
225
|
*/
|
|
210
|
-
pubPermSubs(context: JobState, jobOutput: JobOutput, emit?: boolean): Promise<void>;
|
|
226
|
+
pubPermSubs(context: JobState, jobOutput: JobOutput, emit?: boolean, transaction?: ProviderTransaction): Promise<void>;
|
|
211
227
|
/**
|
|
212
228
|
* @private
|
|
213
229
|
*/
|
|
@@ -227,7 +243,7 @@ declare class EngineService {
|
|
|
227
243
|
/**
|
|
228
244
|
* @private
|
|
229
245
|
*/
|
|
230
|
-
runJobCompletionTasks(context: JobState, options?: JobCompletionOptions): Promise<string | void>;
|
|
246
|
+
runJobCompletionTasks(context: JobState, options?: JobCompletionOptions, transaction?: ProviderTransaction): Promise<string | void>;
|
|
231
247
|
/**
|
|
232
248
|
* Job hash expiration is typically reliant on the metadata field
|
|
233
249
|
* if the activity concludes normally. However, if the job is `interrupted`,
|