@hotmeshio/hotmesh 0.0.54 → 0.0.56

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.
Files changed (182) hide show
  1. package/README.md +0 -3
  2. package/build/modules/enums.js +1 -10
  3. package/build/modules/key.d.ts +0 -38
  4. package/build/modules/key.js +4 -46
  5. package/build/modules/utils.d.ts +0 -8
  6. package/build/modules/utils.js +0 -14
  7. package/build/package.json +11 -4
  8. package/build/services/activities/activity.d.ts +0 -28
  9. package/build/services/activities/activity.js +1 -46
  10. package/build/services/activities/await.js +0 -4
  11. package/build/services/activities/cycle.d.ts +0 -7
  12. package/build/services/activities/cycle.js +1 -16
  13. package/build/services/activities/hook.d.ts +0 -6
  14. package/build/services/activities/hook.js +2 -12
  15. package/build/services/activities/interrupt.js +0 -8
  16. package/build/services/activities/signal.d.ts +0 -6
  17. package/build/services/activities/signal.js +0 -15
  18. package/build/services/activities/trigger.d.ts +0 -4
  19. package/build/services/activities/trigger.js +1 -7
  20. package/build/services/activities/worker.js +0 -4
  21. package/build/services/collator/index.d.ts +0 -70
  22. package/build/services/collator/index.js +1 -91
  23. package/build/services/compiler/deployer.js +6 -38
  24. package/build/services/compiler/index.d.ts +0 -15
  25. package/build/services/compiler/index.js +0 -20
  26. package/build/services/compiler/validator.d.ts +0 -3
  27. package/build/services/compiler/validator.js +0 -25
  28. package/build/services/connector/clients/ioredis.d.ts +2 -2
  29. package/build/services/connector/clients/ioredis.js +0 -2
  30. package/build/services/connector/clients/redis.d.ts +4 -4
  31. package/build/services/connector/clients/redis.js +1 -3
  32. package/build/services/connector/index.d.ts +1 -1
  33. package/build/services/connector/index.js +0 -2
  34. package/build/services/durable/client.d.ts +1 -26
  35. package/build/services/durable/client.js +0 -56
  36. package/build/services/durable/exporter.d.ts +0 -22
  37. package/build/services/durable/exporter.js +1 -30
  38. package/build/services/durable/handle.d.ts +0 -36
  39. package/build/services/durable/handle.js +0 -46
  40. package/build/services/durable/index.d.ts +0 -4
  41. package/build/services/durable/index.js +0 -4
  42. package/build/services/durable/schemas/factory.d.ts +0 -29
  43. package/build/services/durable/schemas/factory.js +0 -29
  44. package/build/services/durable/search.d.ts +1 -36
  45. package/build/services/durable/search.js +57 -56
  46. package/build/services/durable/worker.js +2 -22
  47. package/build/services/durable/workflow.d.ts +0 -114
  48. package/build/services/durable/workflow.js +4 -144
  49. package/build/services/engine/index.d.ts +1 -6
  50. package/build/services/engine/index.js +1 -43
  51. package/build/services/exporter/index.d.ts +0 -27
  52. package/build/services/exporter/index.js +0 -33
  53. package/build/services/hotmesh/index.d.ts +2 -2
  54. package/build/services/hotmesh/index.js +1 -9
  55. package/build/services/logger/index.js +0 -2
  56. package/build/services/mapper/index.d.ts +0 -14
  57. package/build/services/mapper/index.js +0 -14
  58. package/build/services/pipe/functions/date.d.ts +0 -7
  59. package/build/services/pipe/functions/date.js +0 -7
  60. package/build/services/pipe/functions/math.js +0 -2
  61. package/build/services/pipe/index.d.ts +0 -15
  62. package/build/services/pipe/index.js +2 -23
  63. package/build/services/quorum/index.d.ts +0 -7
  64. package/build/services/quorum/index.js +0 -21
  65. package/build/services/reporter/index.d.ts +0 -5
  66. package/build/services/reporter/index.js +0 -9
  67. package/build/services/router/index.d.ts +0 -9
  68. package/build/services/router/index.js +2 -38
  69. package/build/services/serializer/index.js +7 -26
  70. package/build/services/store/cache.d.ts +0 -18
  71. package/build/services/store/cache.js +0 -18
  72. package/build/services/store/clients/ioredis.d.ts +1 -1
  73. package/build/services/store/clients/ioredis.js +0 -1
  74. package/build/services/store/clients/redis.d.ts +1 -1
  75. package/build/services/store/index.d.ts +0 -55
  76. package/build/services/store/index.js +5 -81
  77. package/build/services/stream/clients/ioredis.d.ts +1 -1
  78. package/build/services/stream/clients/ioredis.js +1 -4
  79. package/build/services/stream/clients/redis.d.ts +1 -1
  80. package/build/services/sub/clients/ioredis.d.ts +1 -1
  81. package/build/services/sub/clients/redis.d.ts +1 -1
  82. package/build/services/task/index.d.ts +0 -9
  83. package/build/services/task/index.js +0 -31
  84. package/build/services/telemetry/index.d.ts +0 -7
  85. package/build/services/telemetry/index.js +1 -13
  86. package/build/services/worker/index.d.ts +0 -4
  87. package/build/services/worker/index.js +2 -6
  88. package/build/types/activity.d.ts +0 -81
  89. package/build/types/durable.d.ts +25 -177
  90. package/build/types/exporter.d.ts +0 -13
  91. package/build/types/hotmesh.d.ts +4 -16
  92. package/build/types/hotmesh.js +0 -3
  93. package/build/types/index.d.ts +4 -6
  94. package/build/types/index.js +4 -3
  95. package/build/types/job.d.ts +1 -86
  96. package/build/types/pipe.d.ts +0 -65
  97. package/build/types/quorum.d.ts +15 -10
  98. package/build/types/redis.d.ts +225 -7
  99. package/build/types/redis.js +9 -0
  100. package/build/types/stream.d.ts +0 -58
  101. package/build/types/stream.js +0 -4
  102. package/package.json +11 -4
  103. package/types/durable.ts +121 -3
  104. package/types/hotmesh.ts +3 -6
  105. package/types/index.ts +23 -10
  106. package/types/job.ts +1 -1
  107. package/types/quorum.ts +22 -0
  108. package/types/redis.ts +267 -18
  109. package/build/types/ioredisclient.d.ts +0 -5
  110. package/build/types/ioredisclient.js +0 -5
  111. package/build/types/redisclient.d.ts +0 -26
  112. package/build/types/redisclient.js +0 -2
  113. package/modules/enums.ts +0 -62
  114. package/modules/errors.ts +0 -280
  115. package/modules/key.ts +0 -101
  116. package/modules/storage.ts +0 -3
  117. package/modules/utils.ts +0 -242
  118. package/services/activities/activity.ts +0 -589
  119. package/services/activities/await.ts +0 -113
  120. package/services/activities/cycle.ts +0 -115
  121. package/services/activities/hook.ts +0 -197
  122. package/services/activities/index.ts +0 -19
  123. package/services/activities/interrupt.ts +0 -172
  124. package/services/activities/signal.ts +0 -148
  125. package/services/activities/trigger.ts +0 -295
  126. package/services/activities/worker.ts +0 -107
  127. package/services/collator/README.md +0 -102
  128. package/services/collator/index.ts +0 -291
  129. package/services/compiler/deployer.ts +0 -504
  130. package/services/compiler/index.ts +0 -98
  131. package/services/compiler/validator.ts +0 -158
  132. package/services/connector/clients/ioredis.ts +0 -57
  133. package/services/connector/clients/redis.ts +0 -72
  134. package/services/connector/index.ts +0 -42
  135. package/services/durable/client.ts +0 -266
  136. package/services/durable/connection.ts +0 -10
  137. package/services/durable/exporter.ts +0 -232
  138. package/services/durable/handle.ts +0 -160
  139. package/services/durable/index.ts +0 -27
  140. package/services/durable/schemas/factory.ts +0 -2358
  141. package/services/durable/search.ts +0 -196
  142. package/services/durable/worker.ts +0 -401
  143. package/services/durable/workflow.ts +0 -557
  144. package/services/engine/index.ts +0 -761
  145. package/services/exporter/index.ts +0 -146
  146. package/services/hotmesh/index.ts +0 -237
  147. package/services/logger/index.ts +0 -79
  148. package/services/mapper/index.ts +0 -89
  149. package/services/pipe/functions/array.ts +0 -78
  150. package/services/pipe/functions/bitwise.ts +0 -27
  151. package/services/pipe/functions/conditional.ts +0 -35
  152. package/services/pipe/functions/date.ts +0 -220
  153. package/services/pipe/functions/index.ts +0 -27
  154. package/services/pipe/functions/json.ts +0 -11
  155. package/services/pipe/functions/logical.ts +0 -11
  156. package/services/pipe/functions/math.ts +0 -217
  157. package/services/pipe/functions/number.ts +0 -75
  158. package/services/pipe/functions/object.ts +0 -98
  159. package/services/pipe/functions/string.ts +0 -86
  160. package/services/pipe/functions/symbol.ts +0 -39
  161. package/services/pipe/functions/unary.ts +0 -19
  162. package/services/pipe/index.ts +0 -216
  163. package/services/quorum/index.ts +0 -319
  164. package/services/reporter/index.ts +0 -387
  165. package/services/router/index.ts +0 -426
  166. package/services/serializer/README.md +0 -10
  167. package/services/serializer/index.ts +0 -285
  168. package/services/store/cache.ts +0 -172
  169. package/services/store/clients/ioredis.ts +0 -145
  170. package/services/store/clients/redis.ts +0 -191
  171. package/services/store/index.ts +0 -1091
  172. package/services/stream/clients/ioredis.ts +0 -157
  173. package/services/stream/clients/redis.ts +0 -158
  174. package/services/stream/index.ts +0 -58
  175. package/services/sub/clients/ioredis.ts +0 -83
  176. package/services/sub/clients/redis.ts +0 -74
  177. package/services/sub/index.ts +0 -25
  178. package/services/task/index.ts +0 -250
  179. package/services/telemetry/index.ts +0 -273
  180. package/services/worker/index.ts +0 -248
  181. package/types/ioredisclient.ts +0 -10
  182. package/types/redisclient.ts +0 -30
@@ -1,426 +0,0 @@
1
- import {
2
- HMSH_BLOCK_TIME_MS,
3
- HMSH_MAX_RETRIES,
4
- HMSH_MAX_TIMEOUT_MS,
5
- HMSH_GRADUATED_INTERVAL_MS,
6
- HMSH_CODE_UNACKED,
7
- HMSH_CODE_UNKNOWN,
8
- HMSH_STATUS_UNKNOWN,
9
- HMSH_XCLAIM_COUNT,
10
- HMSH_XCLAIM_DELAY_MS,
11
- HMSH_XPENDING_COUNT } from '../../modules/enums';
12
- import { KeyType } from '../../modules/key';
13
- import { guid, sleepFor } from '../../modules/utils';
14
- import { ILogger } from '../logger';
15
- import { StoreService } from '../store';
16
- import { StreamService } from '../stream';
17
- import { TelemetryService } from '../telemetry';
18
- import { RedisClient, RedisMulti } from '../../types/redis';
19
- import {
20
- ReclaimedMessageType,
21
- StreamConfig,
22
- StreamData,
23
- StreamDataResponse,
24
- StreamDataType,
25
- StreamError,
26
- StreamRole,
27
- StreamStatus
28
- } from '../../types/stream';
29
-
30
- class Router {
31
- static instances: Set<Router> = new Set();
32
- appId: string;
33
- guid: string;
34
- role: StreamRole;
35
- topic: string | undefined;
36
- store: StoreService<RedisClient, RedisMulti>;
37
- stream: StreamService<RedisClient, RedisMulti>;
38
- reclaimDelay: number;
39
- reclaimCount: number;
40
- logger: ILogger;
41
- throttle = 0;
42
- errorCount = 0;
43
- counts: { [key: string]: number } = {};
44
- currentTimerId: NodeJS.Timeout | null = null;
45
- shouldConsume: boolean;
46
- sleepPromiseResolve: (() => void) | null = null;
47
- innerPromiseResolve: (() => void) | null = null;
48
- isSleeping: boolean = false;
49
- sleepTimout: NodeJS.Timeout | null = null;
50
-
51
- constructor(config: StreamConfig, stream: StreamService<RedisClient, RedisMulti>, store: StoreService<RedisClient, RedisMulti>, logger: ILogger) {
52
- this.appId = config.appId;
53
- this.guid = config.guid;
54
- this.role = config.role;
55
- this.topic = config.topic;
56
- this.stream = stream;
57
- this.store = store;
58
- this.reclaimDelay = config.reclaimDelay || HMSH_XCLAIM_DELAY_MS;
59
- this.reclaimCount = config.reclaimCount || HMSH_XCLAIM_COUNT;
60
- this.logger = logger;
61
- this.resetThrottleState();
62
- }
63
-
64
- private resetThrottleState() {
65
- this.sleepPromiseResolve = null;
66
- this.innerPromiseResolve = null;
67
- this.isSleeping = false;
68
- this.sleepTimout = null;
69
- }
70
-
71
- async createGroup(stream: string, group: string) {
72
- try {
73
- await this.store.xgroup('CREATE', stream, group, '$', 'MKSTREAM');
74
- } catch (err) {
75
- this.logger.debug('consumer-group-exists', { stream, group });
76
- }
77
- }
78
-
79
- async publishMessage(topic: string, streamData: StreamData|StreamDataResponse, multi?: RedisMulti): Promise<string | RedisMulti> {
80
- const code = streamData?.code || '200';
81
- this.counts[code] = (this.counts[code] || 0) + 1;
82
-
83
- const stream = this.store.mintKey(KeyType.STREAMS, { appId: this.store.appId, topic });
84
- return await this.store.xadd(stream, '*', 'message', JSON.stringify(streamData), multi);
85
- }
86
-
87
- /**
88
- * An adjustable throttle that will interrupt a sleeping
89
- * router if the throttle is reduced and the sleep time
90
- * has elapsed. If the throttle is increased, or if
91
- * the sleep time has not elapsed, the router will continue
92
- * to sleep until the new termination point. This
93
- * allows for dynamic, elastic throttling with smooth
94
- * acceleration and deceleration.
95
- */
96
- public async customSleep(): Promise<void> {
97
- if (this.throttle === 0) return;
98
- if (this.isSleeping) return;
99
- this.isSleeping = true;
100
- let startTime = Date.now(); //anchor the origin
101
-
102
- await new Promise<void>(async (outerResolve) => {
103
- this.sleepPromiseResolve = outerResolve;
104
- let elapsedTime = Date.now() - startTime;
105
- while (elapsedTime < this.throttle) {
106
- await new Promise<void>((innerResolve) => {
107
- this.innerPromiseResolve = innerResolve;
108
- this.sleepTimout = setTimeout(innerResolve, this.throttle - elapsedTime);
109
- });
110
- elapsedTime = Date.now() - startTime;
111
- }
112
- this.resetThrottleState();
113
- outerResolve();
114
- });
115
- }
116
-
117
- async consumeMessages(stream: string, group: string, consumer: string, callback: (streamData: StreamData) => Promise<StreamDataResponse|void>): Promise<void> {
118
- this.logger.info(`stream-consumer-starting`, { group, consumer, stream });
119
- Router.instances.add(this);
120
- this.shouldConsume = true;
121
- await this.createGroup(stream, group);
122
- let lastCheckedPendingMessagesAt = Date.now();
123
-
124
- async function consume() {
125
- await this.customSleep();
126
- if (!this.shouldConsume) {
127
- this.logger.info(`stream-consumer-stopping`, { group, consumer, stream });
128
- return;
129
- }
130
-
131
- try {
132
- //randomizer that asymptotes at 150% of `HMSH_BLOCK_TIME_MS`
133
- const streamDuration = HMSH_BLOCK_TIME_MS + Math.round((HMSH_BLOCK_TIME_MS * Math.random()));
134
- const result = await this.stream.xreadgroup('GROUP', group, consumer, 'BLOCK', streamDuration, 'STREAMS', stream, '>');
135
- if (this.isStreamMessage(result)) {
136
- const [[, messages]] = result;
137
- for (const [id, message] of messages) {
138
- await this.consumeOne(stream, group, id, message, callback);
139
- }
140
- }
141
-
142
- // Check for pending messages (note: Redis 6.2 simplifies)
143
- const now = Date.now();
144
- if (now - lastCheckedPendingMessagesAt > this.reclaimDelay) {
145
- lastCheckedPendingMessagesAt = now;
146
- const pendingMessages = await this.claimUnacknowledged(stream, group, consumer);
147
- for (const [id, message] of pendingMessages) {
148
- await this.consumeOne(stream, group, id, message, callback);
149
- }
150
- }
151
- setImmediate(consume.bind(this));
152
- } catch (err) {
153
- if (this.shouldConsume && process.env.NODE_ENV !== 'test') {
154
- this.logger.error(`stream-consume-message-error`, { err, stream, group, consumer });
155
- this.errorCount++;
156
- const timeout = Math.min(HMSH_GRADUATED_INTERVAL_MS * (2 ** this.errorCount), HMSH_MAX_TIMEOUT_MS);
157
- setTimeout(consume.bind(this), timeout);
158
- }
159
- }
160
- }
161
- consume.call(this);
162
- }
163
-
164
- isStreamMessage(result: any): boolean {
165
- return Array.isArray(result) && Array.isArray(result[0])
166
- }
167
-
168
- async consumeOne(stream: string, group: string, id: string, message: string[], callback: (streamData: StreamData) => Promise<StreamDataResponse|void>) {
169
- this.logger.debug(`stream-consume-one`, { group, stream, id });
170
- const [err, input] = this.parseStreamData(message[1]);
171
- let output: StreamDataResponse | void;
172
- let telemetry: TelemetryService;
173
- try {
174
- telemetry = new TelemetryService(this.appId);
175
- telemetry.startStreamSpan(input, this.role);
176
- output = await this.execStreamLeg(input, stream, id, callback.bind(this));
177
- if (output?.status === StreamStatus.ERROR) {
178
- telemetry.setStreamError(`Function Status Code ${ output.code || HMSH_CODE_UNKNOWN }`);
179
- }
180
- this.errorCount = 0;
181
- } catch (err) {
182
- this.logger.error(`stream-consume-one-error`, { group, stream, id, err });
183
- telemetry.setStreamError(err.message);
184
- }
185
- const messageId = await this.publishResponse(input, output);
186
- telemetry.setStreamAttributes({ 'app.worker.mid': messageId });
187
- await this.ackAndDelete(stream, group, id);
188
- telemetry.endStreamSpan();
189
- this.logger.debug(`stream-consume-one-end`, { group, stream, id });
190
- }
191
-
192
- async execStreamLeg(input: StreamData, stream: string, id: string, callback: (streamData: StreamData) => Promise<StreamDataResponse|void>) {
193
- let output: StreamDataResponse | void;
194
- try {
195
- output = await callback(input);
196
- } catch (error) {
197
- this.logger.error(`stream-call-function-error`, { ...error, input: input, stack: error.stack, message: error.message, name: error.name, stream, id });
198
- output = this.structureUnhandledError(input, error);
199
- }
200
- return output as StreamDataResponse;
201
- }
202
-
203
- async ackAndDelete(stream: string, group: string, id: string) {
204
- const multi = this.stream.getMulti();
205
- await this.stream.xack(stream, group, id, multi);
206
- await this.stream.xdel(stream, id, multi);
207
- await multi.exec();
208
- }
209
-
210
- async publishResponse(input: StreamData, output: StreamDataResponse | void): Promise<string> {
211
- if (output && typeof output === 'object') {
212
- if (output.status === 'error') {
213
- const [shouldRetry, timeout] = this.shouldRetry(input, output);
214
- if (shouldRetry) {
215
- await sleepFor(timeout);
216
- return await this.publishMessage(input.metadata.topic, {
217
- data: input.data,
218
- //note: retain guid (this is a retry attempt)
219
- metadata: { ...input.metadata, try: (input.metadata.try || 0) + 1 },
220
- policies: input.policies,
221
- }) as string;
222
- } else {
223
- output = this.structureError(input, output);
224
- }
225
- } else if (typeof output.metadata !== 'object') {
226
- output.metadata = { ...input.metadata, guid: guid() };
227
- } else {
228
- output.metadata.guid = guid();
229
- }
230
- output.type = StreamDataType.RESPONSE;
231
- return await this.publishMessage(null, output as StreamDataResponse) as string;
232
- }
233
- }
234
-
235
- shouldRetry(input: StreamData, output: StreamDataResponse): [boolean, number] {
236
- //const isUnhandledEngineError = output.code === 500;
237
- const policies = input.policies?.retry;
238
- const errorCode = output.code.toString();
239
- const policy = policies?.[errorCode];
240
- const maxRetries = policy?.[0];
241
- // if (isUnhandledEngineError && !policy) {
242
- // //if main goes down, replicas take over within 5s
243
- // //if this is not system/platform related, the exponential
244
- // //backoff will be applied and eventually slow to a crawl while
245
- // //the root cause is identified
246
- // input.policies = { retry: { [errorCode]: [10] } };
247
- // return [true, 0];
248
- // }
249
- const tryCount = Math.min(input.metadata.try || 0, HMSH_MAX_RETRIES);
250
- //only possible values for maxRetries are 1, 2, 3
251
- //only possible values for tryCount are 0, 1, 2
252
- if (maxRetries > tryCount) {
253
- // 10ms, 100ms, or 1000ms delays between system retries
254
- return[true, Math.pow(10, tryCount + 1)];
255
- }
256
- return [false, 0];
257
- }
258
-
259
- structureUnhandledError(input: StreamData, err: Error): StreamDataResponse {
260
- let error: Partial<StreamError> = {};
261
- if (typeof err.message === 'string') {
262
- error.message = err.message;
263
- } else {
264
- error.message = HMSH_STATUS_UNKNOWN;
265
- }
266
- if (typeof err.stack === 'string') {
267
- error.stack = err.stack;
268
- }
269
- if (typeof err.name === 'string') {
270
- error.name = err.name;
271
- }
272
- return {
273
- status: 'error',
274
- code: HMSH_CODE_UNKNOWN,
275
- metadata: { ...input.metadata, guid: guid() },
276
- data: error as StreamError
277
- } as StreamDataResponse;
278
- }
279
-
280
- structureUnacknowledgedError(input: StreamData) {
281
- const message = 'stream message max delivery count exceeded';
282
- const code = HMSH_CODE_UNACKED;
283
- const data: StreamError = { message, code };
284
- const output: StreamDataResponse = {
285
- metadata: { ...input.metadata, guid: guid() },
286
- status: StreamStatus.ERROR,
287
- code,
288
- data,
289
- };
290
- //send unacknowleded errors to the engine (it has no topic)
291
- delete output.metadata.topic;
292
- return output;
293
- }
294
-
295
- structureError(input: StreamData, output: StreamDataResponse): StreamDataResponse {
296
- const message = output.data?.message ? output.data?.message.toString() : HMSH_STATUS_UNKNOWN;
297
- const statusCode = output.code || output.data?.code;
298
- const code = isNaN(statusCode as number) ? HMSH_CODE_UNKNOWN : parseInt(statusCode.toString());
299
- const stack = output.data?.stack ? output.data?.stack.toString() : undefined;
300
- const data: StreamError = { message, code, stack };
301
- if (typeof output.data?.error === 'object') {
302
- data.error = { ...output.data.error };
303
- }
304
- return {
305
- status: StreamStatus.ERROR,
306
- code,
307
- stack,
308
- metadata: { ...input.metadata, guid: guid() },
309
- data
310
- } as StreamDataResponse;
311
- }
312
-
313
- static async stopConsuming() {
314
- for (const instance of [...Router.instances]) {
315
- instance.stopConsuming();
316
- }
317
- await sleepFor(HMSH_BLOCK_TIME_MS * 2);
318
- }
319
-
320
- async stopConsuming() {
321
- this.shouldConsume = false;
322
- this.logger.info(`stream-consumer-stopping`, this.topic ? { topic: this.topic } : undefined);
323
- this.cancelThrottle();
324
- }
325
-
326
- cancelThrottle() {
327
- if (this.sleepTimout) {
328
- clearTimeout(this.sleepTimout);
329
- }
330
- this.resetThrottleState();
331
- }
332
-
333
- public setThrottle(delayInMillis: number): void {
334
- if (!Number.isInteger(delayInMillis) || delayInMillis < 0) {
335
- throw new Error('Throttle must be a non-negative integer');
336
- }
337
- const wasDecreased = delayInMillis < this.throttle;
338
- this.throttle = delayInMillis;
339
-
340
- // If the throttle was decreased, and we're in the middle of a sleep cycle, adjust immediately
341
- if (wasDecreased) {
342
- if (this.sleepTimout) {
343
- clearTimeout(this.sleepTimout);
344
- }
345
- if (this.innerPromiseResolve) {
346
- this.innerPromiseResolve();
347
- }
348
- }
349
- }
350
-
351
- async claimUnacknowledged(stream: string, group: string, consumer: string, idleTimeMs = this.reclaimDelay, limit = HMSH_XPENDING_COUNT): Promise<[string, [string, string]][]> {
352
- let pendingMessages = [];
353
- const pendingMessagesInfo = await this.stream.xpending(stream, group, '-', '+', limit); //[[ '1688768134881-0', 'testConsumer1', 1017, 1 ]]
354
- for (const pendingMessageInfo of pendingMessagesInfo) {
355
- if (Array.isArray(pendingMessageInfo)) {
356
- const [id, , elapsedTimeMs, deliveryCount] = pendingMessageInfo;
357
- if (elapsedTimeMs > idleTimeMs) {
358
- const reclaimedMessage = await this.stream.xclaim(stream, group, consumer, idleTimeMs, id);
359
- if (reclaimedMessage.length) {
360
- if (deliveryCount <= this.reclaimCount) {
361
- pendingMessages = pendingMessages.concat(reclaimedMessage);
362
- } else {
363
- await this.expireUnacknowledged(reclaimedMessage, stream, group, consumer, id, deliveryCount);
364
- }
365
- }
366
- }
367
- }
368
- }
369
- return pendingMessages;
370
- }
371
-
372
- async expireUnacknowledged(reclaimedMessage: ReclaimedMessageType, stream: string, group: string, consumer: string, id: string, count: number) {
373
- //The stream activity was not processed within established limits. Possibilities Include:
374
- // 1) user error: the workers were not properly configured and are timing out
375
- // 2a) system error: JSON is corrupt
376
- // i) unwitting actor
377
- // ii) corrupt hardware/network/transport/etc
378
- // 3b) system error: Redis unable to accept `xadd` request
379
- // 4c) system error: Redis unable to accept `xdel`/`xack` request
380
- this.logger.error('stream-message-max-delivery-count-exceeded', { id, stream, group, consumer, code: HMSH_CODE_UNACKED, count });
381
- const streamData = reclaimedMessage[0]?.[1]?.[1];
382
-
383
- //fatal risk point 1 of 3): json is corrupt
384
- const [err, input] = this.parseStreamData(streamData as string);
385
- if (err) {
386
- return this.logger.error('expire-unacknowledged-parse-fatal-error', { id, err })
387
- } else if(!input || !input.metadata) {
388
- return this.logger.error('expire-unacknowledged-parse-fatal-error', { id })
389
- }
390
- let telemetry: TelemetryService;
391
- let messageId: string;
392
- try {
393
- telemetry = new TelemetryService(this.appId);
394
- telemetry.startStreamSpan(input, StreamRole.SYSTEM);
395
- telemetry.setStreamError(`Stream Message Max Delivery Count Exceeded`);
396
-
397
- //fatal risk point 2 of 3): unable to publish error message (to notify the parent job)
398
- const output = this.structureUnacknowledgedError(input);
399
- messageId = await this.publishResponse(input, output);
400
- telemetry.setStreamAttributes({ 'app.worker.mid': messageId });
401
-
402
- //fatal risk point 3 of 3): unable to ack and delete stream message
403
- await this.ackAndDelete(stream, group, id);
404
- } catch (err) {
405
- if (messageId) {
406
- this.logger.error('expire-unacknowledged-pub-fatal-error', { id, err, ...input.metadata });
407
- telemetry.setStreamAttributes({ 'app.system.fatal': 'expire-unacknowledged-pub-fatal-error' });
408
- } else {
409
- this.logger.error('expire-unacknowledged-ack-fatal-error', { id, err, ...input.metadata });
410
- telemetry.setStreamAttributes({ 'app.system.fatal': 'expire-unacknowledged-ack-fatal-error' });
411
- }
412
- } finally {
413
- telemetry.endStreamSpan();
414
- }
415
- }
416
-
417
- parseStreamData(str: string): [undefined, StreamData] | [Error] {
418
- try {
419
- return [,JSON.parse(str)];
420
- } catch (e) {
421
- return [e as Error];
422
- }
423
- }
424
- }
425
-
426
- export { Router };
@@ -1,10 +0,0 @@
1
- # Serializer Overview
2
- ## Sym Keys
3
- Each activity/job is granted 286 tranche of symbols (26 for metadata keys, 260 for data keys).
4
-
5
- Typically, 5-10 symbols are used for metadata (aid, atp, etc), but it allows for future expansion. The 260 remaining data symbols allow for 260 unique scalar mapping statements as it is the mapping statements (the paths to reach the target value) define the symbols to use for data mapping (the symbols represent these paths).
6
-
7
- If `a1` maps to `a1.output.data.abc` and `a2` maps to `a2.output.data.def`, then when `a1` saves its output, it will only save the field values `abc`, and `def`. When saved to the backend it would be: `{a1: {data: { abc: 'somevalue', def: 'another' }}` when flattened and deflated, the keys would be 'bbb' and 'bbc' (or whatever the actual value) and the values would be 'somevalue' and 'another' respectively.
8
-
9
- ## Sym Values
10
- It is possible to replace persisted values. Up to 2,704 possible 2-letter symbols are available for use (52^2) to represent any string value.