@hotmeshio/hotmesh 0.16.0 → 0.16.1
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/build/modules/storage.d.ts +1 -0
- package/build/modules/storage.js +2 -1
- package/build/package.json +1 -1
- package/build/services/pipe/functions/cron.js +4 -1
- package/build/services/task/index.js +1 -1
- package/build/services/virtual/index.d.ts +22 -1
- package/build/services/virtual/index.js +54 -6
- package/build/types/index.d.ts +1 -1
- package/build/types/virtual.d.ts +69 -1
- package/package.json +1 -1
|
@@ -2,3 +2,4 @@
|
|
|
2
2
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
3
3
|
export declare const asyncLocalStorage: AsyncLocalStorage<Map<string, any>>;
|
|
4
4
|
export declare const activityAsyncLocalStorage: AsyncLocalStorage<Map<string, any>>;
|
|
5
|
+
export declare const virtualAsyncLocalStorage: AsyncLocalStorage<Map<string, any>>;
|
package/build/modules/storage.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.activityAsyncLocalStorage = exports.asyncLocalStorage = void 0;
|
|
3
|
+
exports.virtualAsyncLocalStorage = exports.activityAsyncLocalStorage = exports.asyncLocalStorage = void 0;
|
|
4
4
|
const async_hooks_1 = require("async_hooks");
|
|
5
5
|
exports.asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
|
6
6
|
exports.activityAsyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
|
7
|
+
exports.virtualAsyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
package/build/package.json
CHANGED
|
@@ -30,9 +30,12 @@ class CronHandler {
|
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
nextDelay(cronExpression) {
|
|
33
|
-
if (
|
|
33
|
+
if (cronExpression == null || typeof cronExpression !== 'string') {
|
|
34
34
|
return -1;
|
|
35
35
|
}
|
|
36
|
+
if (!(0, utils_1.isValidCron)(cronExpression)) {
|
|
37
|
+
throw new Error(`Invalid cron expression: ${cronExpression}`);
|
|
38
|
+
}
|
|
36
39
|
const interval = (0, cron_parser_1.parseExpression)(cronExpression, { utc: true });
|
|
37
40
|
const nextDate = interval.next().toDate();
|
|
38
41
|
const now = new Date();
|
|
@@ -42,7 +42,7 @@ class TaskService {
|
|
|
42
42
|
async registerTimeHook(jobId, gId, activityId, type, inSeconds = enums_1.HMSH_FIDELITY_SECONDS, dad, transaction) {
|
|
43
43
|
const fromNow = Date.now() + inSeconds * 1000;
|
|
44
44
|
const fidelityMS = enums_1.HMSH_FIDELITY_SECONDS * 1000;
|
|
45
|
-
const awakenTimeSlot = Math.
|
|
45
|
+
const awakenTimeSlot = Math.ceil(fromNow / fidelityMS) * fidelityMS;
|
|
46
46
|
await this.store.registerTimeHook(jobId, gId, activityId, type, awakenTimeSlot, dad, transaction);
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HotMesh } from '../hotmesh';
|
|
2
|
-
import { VirtualConnectParams, VirtualCronParams, VirtualExecParams, VirtualFlushParams, VirtualInstanceOptions, VirtualInterruptParams } from '../../types/virtual';
|
|
2
|
+
import { VirtualConnectParams, VirtualContext, VirtualCronParams, VirtualExecParams, VirtualFlushParams, VirtualInstanceOptions, VirtualInterruptParams } from '../../types/virtual';
|
|
3
3
|
import { ProviderConfig, ProvidersConfig } from '../../types/provider';
|
|
4
4
|
/**
|
|
5
5
|
* Virtual creates a virtual network of functions, connecting any
|
|
@@ -185,6 +185,27 @@ declare class Virtual {
|
|
|
185
185
|
* ```
|
|
186
186
|
*/
|
|
187
187
|
static interrupt(params: VirtualInterruptParams): Promise<boolean>;
|
|
188
|
+
/**
|
|
189
|
+
* Returns the execution context for the current Virtual callback.
|
|
190
|
+
* Must be called from inside a `Virtual.cron` or `Virtual.exec`
|
|
191
|
+
* callback — throws if called outside that scope.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* await Virtual.cron({
|
|
196
|
+
* topic: 'my.cron',
|
|
197
|
+
* connection,
|
|
198
|
+
* args: [],
|
|
199
|
+
* options: { id: 'daily', interval: '0 0 * * *' },
|
|
200
|
+
* callback: async () => {
|
|
201
|
+
* const ctx = Virtual.getContext();
|
|
202
|
+
* console.log(ctx.workflowId); // 'daily'
|
|
203
|
+
* console.log(ctx.attempt); // 1
|
|
204
|
+
* },
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
static getContext(): VirtualContext;
|
|
188
209
|
/**
|
|
189
210
|
* Shuts down all virtual instances. Call this method
|
|
190
211
|
* from the SIGTERM handler in your application.
|
|
@@ -6,8 +6,14 @@ const hotmesh_1 = require("../hotmesh");
|
|
|
6
6
|
const enums_1 = require("../../modules/enums");
|
|
7
7
|
const utils_1 = require("../../modules/utils");
|
|
8
8
|
const key_1 = require("../../modules/key");
|
|
9
|
+
const storage_1 = require("../../modules/storage");
|
|
9
10
|
const cron_1 = require("../pipe/functions/cron");
|
|
10
11
|
const factory_1 = require("./schemas/factory");
|
|
12
|
+
const DEFAULT_RETRY_POLICY = {
|
|
13
|
+
maximumAttempts: 3,
|
|
14
|
+
backoffCoefficient: 2,
|
|
15
|
+
maximumInterval: 30,
|
|
16
|
+
};
|
|
11
17
|
/**
|
|
12
18
|
* Virtual creates a virtual network of functions, connecting any
|
|
13
19
|
* function as an idempotent, cacheable endpoint. Call functions
|
|
@@ -173,13 +179,19 @@ class Virtual {
|
|
|
173
179
|
{
|
|
174
180
|
topic: params.topic,
|
|
175
181
|
connection,
|
|
176
|
-
retry: params.retry ??
|
|
177
|
-
maximumAttempts: 3,
|
|
178
|
-
backoffCoefficient: 2,
|
|
179
|
-
maximumInterval: 30,
|
|
180
|
-
},
|
|
182
|
+
retry: params.retry ?? DEFAULT_RETRY_POLICY,
|
|
181
183
|
callback: async function (input) {
|
|
182
|
-
const
|
|
184
|
+
const context = new Map([
|
|
185
|
+
['topic', params.topic],
|
|
186
|
+
['workflowId', input.metadata.jid ?? ''],
|
|
187
|
+
['workflowName', input.metadata.wfn ?? ''],
|
|
188
|
+
['dimension', input.metadata.dad ?? ''],
|
|
189
|
+
['attempt', input.metadata.try ?? 1],
|
|
190
|
+
['guid', input.metadata.guid],
|
|
191
|
+
['traceId', input.metadata.trc ?? ''],
|
|
192
|
+
['spanId', input.metadata.spn ?? ''],
|
|
193
|
+
]);
|
|
194
|
+
const response = await storage_1.virtualAsyncLocalStorage.run(context, () => params.callback.apply(this, input.data.args));
|
|
183
195
|
return {
|
|
184
196
|
metadata: { ...input.metadata },
|
|
185
197
|
data: { response },
|
|
@@ -386,6 +398,42 @@ class Virtual {
|
|
|
386
398
|
}
|
|
387
399
|
return true;
|
|
388
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Returns the execution context for the current Virtual callback.
|
|
403
|
+
* Must be called from inside a `Virtual.cron` or `Virtual.exec`
|
|
404
|
+
* callback — throws if called outside that scope.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* await Virtual.cron({
|
|
409
|
+
* topic: 'my.cron',
|
|
410
|
+
* connection,
|
|
411
|
+
* args: [],
|
|
412
|
+
* options: { id: 'daily', interval: '0 0 * * *' },
|
|
413
|
+
* callback: async () => {
|
|
414
|
+
* const ctx = Virtual.getContext();
|
|
415
|
+
* console.log(ctx.workflowId); // 'daily'
|
|
416
|
+
* console.log(ctx.attempt); // 1
|
|
417
|
+
* },
|
|
418
|
+
* });
|
|
419
|
+
* ```
|
|
420
|
+
*/
|
|
421
|
+
static getContext() {
|
|
422
|
+
const store = storage_1.virtualAsyncLocalStorage.getStore();
|
|
423
|
+
if (!store) {
|
|
424
|
+
throw new Error('Virtual.getContext() called outside of a Virtual callback execution context');
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
topic: store.get('topic'),
|
|
428
|
+
workflowId: store.get('workflowId'),
|
|
429
|
+
workflowName: store.get('workflowName'),
|
|
430
|
+
dimension: store.get('dimension'),
|
|
431
|
+
attempt: store.get('attempt'),
|
|
432
|
+
guid: store.get('guid'),
|
|
433
|
+
traceId: store.get('traceId'),
|
|
434
|
+
spanId: store.get('spanId'),
|
|
435
|
+
};
|
|
436
|
+
}
|
|
389
437
|
/**
|
|
390
438
|
* Shuts down all virtual instances. Call this method
|
|
391
439
|
* from the SIGTERM handler in your application.
|
package/build/types/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { ExtensionType, JobCompletionOptions, JobData, JobsData, JobInterruptOpt
|
|
|
15
15
|
export { MappingStatements } from './map';
|
|
16
16
|
export { Pipe, PipeContext, PipeItem, PipeItems, PipeObject, ReduceObject, } from './pipe';
|
|
17
17
|
export { ProviderClass, ProviderClient, ProviderConfig, ProviderTransaction, Providers, TransactionResultList, ProviderNativeClient, ProviderOptions, } from './provider';
|
|
18
|
-
export { VirtualConnectParams, VirtualExecParams, VirtualCronParams, VirtualExecOptions, VirtualCronOptions, VirtualInterruptOptions, VirtualInterruptParams, VirtualFlushParams, } from './virtual';
|
|
18
|
+
export { VirtualConnectParams, VirtualContext, VirtualExecParams, VirtualCronParams, VirtualExecOptions, VirtualCronOptions, VirtualInterruptOptions, VirtualInterruptParams, VirtualFlushParams, } from './virtual';
|
|
19
19
|
export { PostgresClassType, PostgresClientOptions, PostgresClientType, PostgresConsumerGroup, PostgresPendingMessage, PostgresPoolClientType, PostgresQueryConfigType, PostgresQueryResultType, PostgresStreamMessage, PostgresStreamOptions, PostgresTransaction, } from './postgres';
|
|
20
20
|
export { ActivateMessage, CronMessage, JobMessage, JobMessageCallback, PingMessage, PongMessage, QuorumMessage, QuorumMessageCallback, QuorumProfile, RollCallMessage, RollCallOptions, SubscriptionCallback, SubscriptionOptions, SystemHealth, ThrottleMessage, ThrottleOptions, WorkMessage, } from './quorum';
|
|
21
21
|
export { NatsAckPolicy, NatsAckPolicyExplicitType, NatsClassType, NatsClientType, NatsClientOptions, NatsConsumerConfigType, NatsJetStreamManager, NatsConnection, NatsJetStreamType, NatsConnectionOptions, NatsConsumerConfig, NatsConsumerInfo, NatsConsumerManager, NatsDeliveryInfo, NatsJetStreamOptions, NatsError, NatsErrorType, NatsJetStreamClient, NatsJsMsg, NatsMessageType, NatsMsgExpect, NatsPubAck, NatsPubAckType, NatsPublishOptions, NatsRetentionPolicy, NatsRetentionPolicyWorkqueueType, NatsSequenceInfo, NatsStorageMemoryType, NatsStorageType, NatsStreamConfig, NatsStreamInfo, NatsStreamManager, NatsStreamConfigType, NatsStreamInfoType, NatsStreamOptions, NatsStreamState, NatsTransaction, } from './nats';
|
package/build/types/virtual.d.ts
CHANGED
|
@@ -208,4 +208,72 @@ interface VirtualInterruptParams {
|
|
|
208
208
|
*/
|
|
209
209
|
options: VirtualInterruptOptions;
|
|
210
210
|
}
|
|
211
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Execution context available inside Virtual callbacks via
|
|
213
|
+
* `Virtual.getContext()`. Populated automatically by the
|
|
214
|
+
* AsyncLocalStorage wrapper in `Virtual.connect()`.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* await Virtual.cron({
|
|
219
|
+
* topic: 'billing.daily',
|
|
220
|
+
* connection,
|
|
221
|
+
* args: [],
|
|
222
|
+
* options: { id: 'billing-run', interval: '0 0 * * *' },
|
|
223
|
+
* callback: async () => {
|
|
224
|
+
* const ctx = Virtual.getContext();
|
|
225
|
+
* // ctx.workflowId === 'billing-run'
|
|
226
|
+
* // ctx.topic === 'billing.daily'
|
|
227
|
+
* // ctx.guid === unique per invocation
|
|
228
|
+
* },
|
|
229
|
+
* });
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
interface VirtualContext {
|
|
233
|
+
/**
|
|
234
|
+
* The worker topic that routed this invocation.
|
|
235
|
+
* Matches the `topic` passed to `Virtual.cron()` or
|
|
236
|
+
* `Virtual.connect()`.
|
|
237
|
+
*/
|
|
238
|
+
topic: string;
|
|
239
|
+
/**
|
|
240
|
+
* Workflow / job ID. For cron callbacks this is the `id`
|
|
241
|
+
* from `options.id`. For `Virtual.exec` calls this is the
|
|
242
|
+
* auto-generated or user-supplied job identifier.
|
|
243
|
+
*/
|
|
244
|
+
workflowId: string;
|
|
245
|
+
/**
|
|
246
|
+
* Internal workflow name (the graph subscription topic,
|
|
247
|
+
* e.g. `hmsh.cron` or `hmsh.call`).
|
|
248
|
+
*/
|
|
249
|
+
workflowName: string;
|
|
250
|
+
/**
|
|
251
|
+
* Dimensional address for this execution within the
|
|
252
|
+
* workflow's DAG. Encodes the cycle iteration and
|
|
253
|
+
* parallel branch position.
|
|
254
|
+
*/
|
|
255
|
+
dimension: string;
|
|
256
|
+
/**
|
|
257
|
+
* Current retry attempt (1-based). `1` on the first try,
|
|
258
|
+
* incremented on each retry per the `RetryPolicy`.
|
|
259
|
+
*/
|
|
260
|
+
attempt: number;
|
|
261
|
+
/**
|
|
262
|
+
* Globally unique identifier for the stream message that
|
|
263
|
+
* triggered this callback. A new GUID is minted for every
|
|
264
|
+
* invocation, including retries and cycle iterations, so it
|
|
265
|
+
* serves as an idempotency key for exactly-once processing.
|
|
266
|
+
*/
|
|
267
|
+
guid: string;
|
|
268
|
+
/**
|
|
269
|
+
* OpenTelemetry trace ID propagated from the originating
|
|
270
|
+
* workflow. Empty string when tracing is not configured.
|
|
271
|
+
*/
|
|
272
|
+
traceId: string;
|
|
273
|
+
/**
|
|
274
|
+
* OpenTelemetry span ID propagated from the parent activity.
|
|
275
|
+
* Empty string when tracing is not configured.
|
|
276
|
+
*/
|
|
277
|
+
spanId: string;
|
|
278
|
+
}
|
|
279
|
+
export { VirtualConnectParams, VirtualContext, VirtualExecParams, VirtualCronParams, VirtualExecOptions, VirtualCronOptions, VirtualInterruptOptions, VirtualInterruptParams, VirtualFlushOptions, VirtualFlushParams, VirtualInstanceOptions, };
|