@hotmeshio/hotmesh 0.1.7 → 0.1.9

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/README.md CHANGED
@@ -295,31 +295,31 @@ const hotMesh = await HotMesh.init({
295
295
  ```
296
296
 
297
297
  ### Observability
298
- Workflows and activities are run according to the rules you define, offering [Graph-Oriented](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/system_lifecycle.md#telemetry) telemetry insights into your legacy function executions.
298
+ Workflows and activities are run according to the rules you define, offering [Graph-Oriented](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/system_lifecycle.md#telemetry) telemetry insights into your legacy function executions.
299
299
 
300
300
  ## FAQ
301
- Refer to the [FAQ](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/faq.md) for terminology, definitions, and an exploration of how HotMesh facilitates orchestration use cases.
301
+ Refer to the [FAQ](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/faq.md) for terminology, definitions, and an exploration of how HotMesh facilitates orchestration use cases.
302
302
 
303
303
  ## Quick Start
304
- Refer to the [Quick Start](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/quickstart.md) for sample YAML workflows you can copy, paste, and modify to get started.
304
+ Refer to the [Quick Start](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/quickstart.md) for sample YAML workflows you can copy, paste, and modify to get started.
305
305
 
306
306
  ## Developer Guide
307
- For more details on the complete development process, including information about schemas, APIs, and deployment, consult the [Developer Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/developer_guide.md).
307
+ For more details on the complete development process, including information about schemas, APIs, and deployment, consult the [Developer Guide](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/developer_guide.md).
308
308
 
309
309
  ## Model Driven Development
310
- [Model Driven Development](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/model_driven_development.md) is an established strategy for managing process-oriented tasks. Check out this guide to understand its foundational principles.
310
+ [Model Driven Development](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/model_driven_development.md) is an established strategy for managing process-oriented tasks. Check out this guide to understand its foundational principles.
311
311
 
312
312
  ## Data Mapping
313
- Exchanging data between activities is central to HotMesh. For detailed information on supported functions and the functional mapping syntax (@pipes), see the [Data Mapping Overview](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/data_mapping.md).
313
+ Exchanging data between activities is central to HotMesh. For detailed information on supported functions and the functional mapping syntax (@pipes), see the [Data Mapping Overview](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/data_mapping.md).
314
314
 
315
315
  ## Composition
316
- While the simplest graphs are linear, detailing a consistent sequence of non-cyclical activities, graphs can be layered to represent intricate business scenarios. Some can even be designed to accommodate long-lasting workflows that span months. For more details, check out the [Composable Workflow Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/composable_workflow.md).
316
+ While the simplest graphs are linear, detailing a consistent sequence of non-cyclical activities, graphs can be layered to represent intricate business scenarios. Some can even be designed to accommodate long-lasting workflows that span months. For more details, check out the [Composable Workflow Guide](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/composable_workflow.md).
317
317
 
318
318
  ## System Lifecycle
319
- Gain insight into HotMesh's monitoring, exception handling, and alarm configurations via the [System Lifecycle Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/system_lifecycle.md).
319
+ Gain insight into HotMesh's monitoring, exception handling, and alarm configurations via the [System Lifecycle Guide](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/system_lifecycle.md).
320
320
 
321
321
  ## Distributed Orchestration | System Overview
322
- HotMesh is a distributed orchestration engine. Refer to the [Distributed Orchestration Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/distributed_orchestration.md) for a high-level overview of the approach.
322
+ HotMesh is a distributed orchestration engine. Refer to the [Distributed Orchestration Guide](https://github.com/hotmeshio/sdk-typescript/tree/main/docs/distributed_orchestration.md) for a high-level overview of the approach.
323
323
 
324
324
  ## Distributed Orchestration | System Design
325
325
  HotMesh is more than Redis and TypeScript. The theory that underlies the architecture is applicable to any number of data storage and streaming backends: [A Message-Oriented Approach to Decentralized Process Orchestration](https://zenodo.org/records/12168558).
@@ -5,6 +5,7 @@ import { RedisClient, RedisMulti } from '../types/redis';
5
5
  import { StringAnyType } from '../types/serializer';
6
6
  import { StreamCode, StreamStatus } from '../types/stream';
7
7
  import { SystemHealth } from '../types/quorum';
8
+ export declare const hashOptions: (options: any) => string;
8
9
  export declare function getSystemHealth(): Promise<SystemHealth>;
9
10
  export declare function sleepFor(ms: number): Promise<unknown>;
10
11
  export declare function sleepImmediate(): Promise<void>;
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.restoreHierarchy = exports.getValueByPath = exports.getIndexedHash = exports.getSymVal = exports.getSymKey = exports.formatISODate = exports.getTimeSeries = exports.getSubscriptionTopic = exports.findSubscriptionForTrigger = exports.findTopKey = exports.XSleepFor = exports.matchesStatus = exports.matchesStatusCode = exports.identifyRedisTypeFromClass = exports.polyfill = exports.identifyRedisType = exports.deterministicRandom = exports.guid = exports.deepCopy = exports.sleepImmediate = exports.sleepFor = exports.getSystemHealth = void 0;
6
+ exports.restoreHierarchy = exports.getValueByPath = exports.getIndexedHash = exports.getSymVal = exports.getSymKey = exports.formatISODate = exports.getTimeSeries = exports.getSubscriptionTopic = exports.findSubscriptionForTrigger = exports.findTopKey = exports.XSleepFor = exports.matchesStatus = exports.matchesStatusCode = exports.identifyRedisTypeFromClass = exports.polyfill = exports.identifyRedisType = exports.deterministicRandom = exports.guid = exports.deepCopy = exports.sleepImmediate = exports.sleepFor = exports.getSystemHealth = exports.hashOptions = void 0;
7
7
  const os_1 = __importDefault(require("os"));
8
+ const crypto_1 = require("crypto");
8
9
  const nanoid_1 = require("nanoid");
9
10
  const enums_1 = require("./enums");
10
11
  async function safeExecute(operation, defaultValue) {
@@ -16,10 +17,17 @@ async function safeExecute(operation, defaultValue) {
16
17
  return defaultValue;
17
18
  }
18
19
  }
20
+ const hashOptions = (options) => {
21
+ const str = JSON.stringify(options);
22
+ return (0, crypto_1.createHash)('sha256').update(str).digest('hex');
23
+ };
24
+ exports.hashOptions = hashOptions;
19
25
  async function getSystemHealth() {
20
26
  const totalMemory = os_1.default.totalmem();
21
27
  const freeMemory = os_1.default.freemem();
22
28
  const usedMemory = totalMemory - freeMemory;
29
+ //NOTE: enable the following if desired; for now, only
30
+ // `memory` is emitted when system health is requested
23
31
  //const cpus = os.cpus();
24
32
  // CPU load calculation remains unchanged
25
33
  // const cpuLoad = cpus.map((cpu, i) => {
@@ -28,9 +36,8 @@ async function getSystemHealth() {
28
36
  // const usage = ((total - idle) / total) * 100;
29
37
  // return { [`CPU ${i} Usage`]: `${usage.toFixed(2)}%` };
30
38
  // });
31
- // Wrap each systeminformation call with safeExecute
39
+ // Wrap each systeminformation call with safeExecute (systeminformation npm package)
32
40
  //const networkStats = await safeExecute(si.networkStats(), []);
33
- // Construct the system health object with error handling in mind
34
41
  const systemHealth = {
35
42
  TotalMemoryGB: `${(totalMemory / 1024 / 1024 / 1024).toFixed(2)} GB`,
36
43
  FreeMemoryGB: `${(freeMemory / 1024 / 1024 / 1024).toFixed(2)} GB`,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -84,7 +84,6 @@
84
84
  "js-yaml": "^4.1.0",
85
85
  "ms": "^2.1.3",
86
86
  "nanoid": "^3.3.6",
87
- "systeminformation": "^5.22.2",
88
87
  "winston": "^3.8.2"
89
88
  },
90
89
  "devDependencies": {
@@ -27,19 +27,17 @@ declare class Activity {
27
27
  constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
28
28
  setLeg(leg: ActivityLeg): void;
29
29
  /**
30
- * Upon entering leg 1 of a duplexed activty, verify
31
- * all aspects of the entry including job and activty state
30
+ * Upon entering leg 1 of a duplexed activity
32
31
  */
33
32
  verifyEntry(): Promise<void>;
34
33
  /**
35
- * Upon entering leg 2 of a duplexed activty, verify
36
- * all aspects of the re-entry including job and activty state
34
+ * Upon entering leg 2 of a duplexed activity
37
35
  */
38
36
  verifyReentry(): Promise<number>;
39
37
  processEvent(status?: StreamStatus, code?: StreamCode, type?: 'hook' | 'output'): Promise<void>;
40
- processPending(telemetry: TelemetryService, type: 'hook' | 'output'): Promise<MultiResponseFlags>;
41
- processSuccess(telemetry: TelemetryService, type: 'hook' | 'output'): Promise<MultiResponseFlags>;
42
- processError(telemetry: TelemetryService, type: string): Promise<MultiResponseFlags>;
38
+ processPending(type: 'hook' | 'output'): Promise<MultiResponseFlags>;
39
+ processSuccess(type: 'hook' | 'output'): Promise<MultiResponseFlags>;
40
+ processError(): Promise<MultiResponseFlags>;
43
41
  transitionAdjacent(multiResponse: MultiResponseFlags, telemetry: TelemetryService): Promise<void>;
44
42
  resolveStatus(multiResponse: MultiResponseFlags): number;
45
43
  mapJobData(): void;
@@ -31,8 +31,7 @@ class Activity {
31
31
  this.leg = leg;
32
32
  }
33
33
  /**
34
- * Upon entering leg 1 of a duplexed activty, verify
35
- * all aspects of the entry including job and activty state
34
+ * Upon entering leg 1 of a duplexed activity
36
35
  */
37
36
  async verifyEntry() {
38
37
  this.setLeg(1);
@@ -41,8 +40,7 @@ class Activity {
41
40
  await collator_1.CollatorService.notarizeEntry(this);
42
41
  }
43
42
  /**
44
- * Upon entering leg 2 of a duplexed activty, verify
45
- * all aspects of the re-entry including job and activty state
43
+ * Upon entering leg 2 of a duplexed activity
46
44
  */
47
45
  async verifyReentry() {
48
46
  const guid = this.context.metadata.guid;
@@ -79,13 +77,13 @@ class Activity {
79
77
  telemetry.startActivitySpan(this.leg);
80
78
  let multiResponse;
81
79
  if (status === stream_1.StreamStatus.PENDING) {
82
- multiResponse = await this.processPending(telemetry, type);
80
+ multiResponse = await this.processPending(type);
83
81
  }
84
82
  else if (status === stream_1.StreamStatus.SUCCESS) {
85
- multiResponse = await this.processSuccess(telemetry, type);
83
+ multiResponse = await this.processSuccess(type);
86
84
  }
87
85
  else {
88
- multiResponse = await this.processError(telemetry, type);
86
+ multiResponse = await this.processError();
89
87
  }
90
88
  this.transitionAdjacent(multiResponse, telemetry);
91
89
  }
@@ -120,7 +118,7 @@ class Activity {
120
118
  this.logger.debug('activity-process-event-end', { jid, aid });
121
119
  }
122
120
  }
123
- async processPending(telemetry, type) {
121
+ async processPending(type) {
124
122
  this.bindActivityData(type);
125
123
  this.adjacencyList = await this.filterAdjacent();
126
124
  this.mapJobData();
@@ -130,7 +128,7 @@ class Activity {
130
128
  await this.setStatus(this.adjacencyList.length, multi);
131
129
  return (await multi.exec());
132
130
  }
133
- async processSuccess(telemetry, type) {
131
+ async processSuccess(type) {
134
132
  this.bindActivityData(type);
135
133
  this.adjacencyList = await this.filterAdjacent();
136
134
  this.mapJobData();
@@ -140,7 +138,7 @@ class Activity {
140
138
  await this.setStatus(this.adjacencyList.length - 1, multi);
141
139
  return (await multi.exec());
142
140
  }
143
- async processError(telemetry, type) {
141
+ async processError() {
144
142
  this.bindActivityError(this.data);
145
143
  this.adjacencyList = await this.filterAdjacent();
146
144
  if (!this.adjacencyList.length) {
@@ -20,7 +20,7 @@ export declare class ClientService {
20
20
  * creating the stream. This method will verify that the stream
21
21
  * exists and if not, create it.
22
22
  */
23
- static verifyStream: (workflowTopic: string, namespace?: string) => Promise<HotMesh>;
23
+ verifyStream: (hotMeshClient: HotMesh, workflowTopic: string, namespace?: string) => Promise<void>;
24
24
  search: (hotMeshClient: HotMesh, index: string, query: string[]) => Promise<string[]>;
25
25
  workflow: {
26
26
  start: (options: WorkflowOptions) => Promise<WorkflowHandleService>;
@@ -17,14 +17,14 @@ const factory_1 = require("./schemas/factory");
17
17
  class ClientService {
18
18
  constructor(config) {
19
19
  this.getHotMeshClient = async (workflowTopic, namespace) => {
20
+ //namespace isolation requires the connection options to be hashed
21
+ //as multiple intersecting databases can be used by the same service
22
+ const optionsHash = (0, utils_1.hashOptions)(this.connection.options);
20
23
  const targetNS = namespace ?? factory_1.APP_ID;
21
- if (ClientService.instances.has(targetNS)) {
22
- const hotMeshClient = await ClientService.instances.get(targetNS);
24
+ const connectionNS = `${optionsHash}.${targetNS}`;
25
+ if (ClientService.instances.has(connectionNS)) {
26
+ const hotMeshClient = await ClientService.instances.get(connectionNS);
23
27
  await this.verifyWorkflowActive(hotMeshClient, targetNS);
24
- if (!ClientService.topics.includes(workflowTopic)) {
25
- ClientService.topics.push(workflowTopic);
26
- await ClientService.createStream(hotMeshClient, workflowTopic, namespace);
27
- }
28
28
  return hotMeshClient;
29
29
  }
30
30
  //create and cache an instance
@@ -38,11 +38,24 @@ class ClientService {
38
38
  },
39
39
  },
40
40
  });
41
- ClientService.instances.set(targetNS, hotMeshClient);
42
- await ClientService.createStream(await hotMeshClient, workflowTopic, namespace);
41
+ ClientService.instances.set(connectionNS, hotMeshClient);
43
42
  await this.activateWorkflow(await hotMeshClient, targetNS);
44
43
  return hotMeshClient;
45
44
  };
45
+ /**
46
+ * It is possible for a client to invoke a workflow without first
47
+ * creating the stream. This method will verify that the stream
48
+ * exists and if not, create it.
49
+ */
50
+ this.verifyStream = async (hotMeshClient, workflowTopic, namespace) => {
51
+ const optionsHash = (0, utils_1.hashOptions)(this.connection.options);
52
+ const targetNS = namespace ?? factory_1.APP_ID;
53
+ const targetTopic = `${optionsHash}.${targetNS}.${workflowTopic}`;
54
+ if (!ClientService.topics.includes(targetTopic)) {
55
+ ClientService.topics.push(targetTopic);
56
+ await ClientService.createStream(hotMeshClient, workflowTopic, namespace);
57
+ }
58
+ };
46
59
  this.search = async (hotMeshClient, index, query) => {
47
60
  const store = hotMeshClient.engine.store;
48
61
  if (query[0]?.startsWith('FT.')) {
@@ -56,10 +69,11 @@ class ClientService {
56
69
  const workflowName = options.entity ?? options.workflowName;
57
70
  const trc = options.workflowTrace;
58
71
  const spn = options.workflowSpan;
59
- //NOTE: HotMesh 'workflowTopic' is a created by concatenating
60
- // the taskQueue and workflowName used by the Durable module
72
+ //hotmesh topic is a combination of the durable queue+workflowname
61
73
  const workflowTopic = `${taskQueueName}-${workflowName}`;
62
74
  const hotMeshClient = await this.getHotMeshClient(workflowTopic, options.namespace);
75
+ //verify that the stream channel exists before enqueueing
76
+ await this.verifyStream(hotMeshClient, workflowTopic, options.namespace);
63
77
  const payload = {
64
78
  arguments: [...options.args],
65
79
  originJobId: options.originJobId,
@@ -199,20 +213,4 @@ ClientService.createStream = async (hotMeshClient, workflowTopic, namespace) =>
199
213
  //ignore if already exists
200
214
  }
201
215
  };
202
- /**
203
- * It is possible for a client to invoke a workflow without first
204
- * creating the stream. This method will verify that the stream
205
- * exists and if not, create it.
206
- */
207
- ClientService.verifyStream = async (workflowTopic, namespace) => {
208
- const targetNS = namespace ?? factory_1.APP_ID;
209
- if (ClientService.instances.has(targetNS)) {
210
- const hotMeshClient = await ClientService.instances.get(targetNS);
211
- if (!ClientService.topics.includes(workflowTopic)) {
212
- ClientService.topics.push(workflowTopic);
213
- await ClientService.createStream(hotMeshClient, workflowTopic, namespace);
214
- }
215
- return hotMeshClient;
216
- }
217
- };
218
216
  exports.ClientService = ClientService;
@@ -1,8 +1,7 @@
1
1
  import { HotMeshService as HotMesh } from '../hotmesh';
2
- import { Connection, Registry, WorkerConfig, WorkerOptions } from '../../types/durable';
2
+ import { Registry, WorkerConfig, WorkerOptions } from '../../types/durable';
3
3
  export declare class WorkerService {
4
4
  static activityRegistry: Registry;
5
- static connection: Connection;
6
5
  static instances: Map<string, HotMesh | Promise<HotMesh>>;
7
6
  workflowRunner: HotMesh;
8
7
  activityRunner: HotMesh;
@@ -58,7 +58,6 @@ class WorkerService {
58
58
  return WorkerService.activityRegistry;
59
59
  }
60
60
  static async create(config) {
61
- WorkerService.connection = config.connection;
62
61
  const workflow = config.workflow;
63
62
  const [workflowFunctionName, workflowFunction] = WorkerService.resolveWorkflowTarget(workflow);
64
63
  const baseTopic = `${config.taskQueue}-${workflowFunctionName}`;
@@ -93,9 +92,12 @@ class WorkerService {
93
92
  class: config.connection.class,
94
93
  options: config.connection.options,
95
94
  };
95
+ const targetNamespace = config?.namespace ?? factory_1.APP_ID;
96
+ const optionsHash = (0, utils_1.hashOptions)(config?.connection?.options);
97
+ const targetTopic = `${optionsHash}.${targetNamespace}.${activityTopic}`;
96
98
  const hotMeshWorker = await hotmesh_1.HotMeshService.init({
97
99
  logLevel: config.options?.logLevel ?? enums_1.HMSH_LOGLEVEL,
98
- appId: config.namespace ?? factory_1.APP_ID,
100
+ appId: targetNamespace,
99
101
  engine: { redis: redisConfig },
100
102
  workers: [
101
103
  {
@@ -105,10 +107,9 @@ class WorkerService {
105
107
  },
106
108
  ],
107
109
  });
108
- WorkerService.instances.set(activityTopic, hotMeshWorker);
110
+ WorkerService.instances.set(targetTopic, hotMeshWorker);
109
111
  return hotMeshWorker;
110
112
  }
111
- //this is the linked worker function in the reentrant workflow test
112
113
  wrapActivityFunctions() {
113
114
  return async (data) => {
114
115
  try {
@@ -171,6 +172,9 @@ class WorkerService {
171
172
  class: config.connection.class,
172
173
  options: config.connection.options,
173
174
  };
175
+ const targetNamespace = config?.namespace ?? factory_1.APP_ID;
176
+ const optionsHash = (0, utils_1.hashOptions)(config?.connection?.options);
177
+ const targetTopic = `${optionsHash}.${targetNamespace}.${workflowTopic}`;
174
178
  const hotMeshWorker = await hotmesh_1.HotMeshService.init({
175
179
  logLevel: config.options?.logLevel ?? enums_1.HMSH_LOGLEVEL,
176
180
  appId: config.namespace ?? factory_1.APP_ID,
@@ -183,7 +187,7 @@ class WorkerService {
183
187
  },
184
188
  ],
185
189
  });
186
- WorkerService.instances.set(workflowTopic, hotMeshWorker);
190
+ WorkerService.instances.set(targetTopic, hotMeshWorker);
187
191
  return hotMeshWorker;
188
192
  }
189
193
  wrapWorkflowFunction(workflowFunction, workflowTopic, config) {
@@ -198,6 +202,7 @@ class WorkerService {
198
202
  context.set('canRetry', workflowInput.canRetry);
199
203
  context.set('counter', counter);
200
204
  context.set('interruptionRegistry', interruptionRegistry);
205
+ context.set('connection', config.connection);
201
206
  context.set('namespace', config.namespace ?? factory_1.APP_ID);
202
207
  context.set('raw', data);
203
208
  context.set('workflowId', workflowInput.workflowId);
@@ -373,15 +378,20 @@ _a = WorkerService;
373
378
  WorkerService.activityRegistry = {}; //user's activities
374
379
  WorkerService.instances = new Map();
375
380
  WorkerService.getHotMesh = async (workflowTopic, config, options) => {
376
- if (WorkerService.instances.has(workflowTopic)) {
377
- return await WorkerService.instances.get(workflowTopic);
381
+ const targetNamespace = config?.namespace ?? factory_1.APP_ID;
382
+ const optionsHash = (0, utils_1.hashOptions)(config?.connection?.options);
383
+ const targetTopic = `${optionsHash}.${targetNamespace}.${workflowTopic}`;
384
+ if (WorkerService.instances.has(targetTopic)) {
385
+ return await WorkerService.instances.get(targetTopic);
378
386
  }
379
387
  const hotMeshClient = hotmesh_1.HotMeshService.init({
380
388
  logLevel: options?.logLevel ?? enums_1.HMSH_LOGLEVEL,
381
- appId: config.namespace ?? factory_1.APP_ID,
382
- engine: { redis: { ...WorkerService.connection } },
389
+ appId: targetNamespace,
390
+ engine: {
391
+ redis: { ...config?.connection },
392
+ },
383
393
  });
384
- WorkerService.instances.set(workflowTopic, hotMeshClient);
394
+ WorkerService.instances.set(targetTopic, hotMeshClient);
385
395
  await WorkerService.activateWorkflow(await hotMeshClient);
386
396
  return hotMeshClient;
387
397
  };
@@ -69,6 +69,7 @@ class WorkflowService {
69
69
  const interruptionRegistry = store.get('interruptionRegistry');
70
70
  const workflowDimension = store.get('workflowDimension') ?? '';
71
71
  const workflowTopic = store.get('workflowTopic');
72
+ const connection = store.get('connection');
72
73
  const namespace = store.get('namespace');
73
74
  const originJobId = store.get('originJobId');
74
75
  const workflowTrace = store.get('workflowTrace');
@@ -82,6 +83,7 @@ class WorkflowService {
82
83
  counter: COUNTER.counter,
83
84
  cursor,
84
85
  interruptionRegistry,
86
+ connection,
85
87
  namespace,
86
88
  originJobId,
87
89
  raw,
@@ -100,8 +102,9 @@ class WorkflowService {
100
102
  static async getHotMesh() {
101
103
  const store = storage_1.asyncLocalStorage.getStore();
102
104
  const workflowTopic = store.get('workflowTopic');
105
+ const connection = store.get('connection');
103
106
  const namespace = store.get('namespace');
104
- return await worker_1.WorkerService.getHotMesh(workflowTopic, { namespace });
107
+ return await worker_1.WorkerService.getHotMesh(workflowTopic, { connection, namespace });
105
108
  }
106
109
  /**
107
110
  * Spawns a child workflow and awaits the return.
@@ -315,10 +318,12 @@ class WorkflowService {
315
318
  const workflowId = store.get('workflowId');
316
319
  const workflowDimension = store.get('workflowDimension') ?? '';
317
320
  const workflowTopic = store.get('workflowTopic');
321
+ const connection = store.get('connection');
318
322
  const namespace = store.get('namespace');
319
323
  const COUNTER = store.get('counter');
320
324
  const execIndex = COUNTER.counter = COUNTER.counter + 1;
321
325
  const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic, {
326
+ connection,
322
327
  namespace,
323
328
  });
324
329
  //this ID is used as a item key with a hash (dash prefix ensures no collision)
@@ -347,8 +352,10 @@ class WorkflowService {
347
352
  static async signal(signalId, data) {
348
353
  const store = storage_1.asyncLocalStorage.getStore();
349
354
  const workflowTopic = store.get('workflowTopic');
355
+ const connection = store.get('connection');
350
356
  const namespace = store.get('namespace');
351
357
  const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic, {
358
+ connection,
352
359
  namespace,
353
360
  });
354
361
  if (await WorkflowService.isSideEffectAllowed(hotMeshClient, 'signal')) {
@@ -365,8 +372,9 @@ class WorkflowService {
365
372
  * @param {HookOptions} options - the hook options
366
373
  */
367
374
  static async hook(options) {
368
- const { workflowId, namespace, workflowTopic } = WorkflowService.getContext();
375
+ const { workflowId, connection, namespace, workflowTopic } = WorkflowService.getContext();
369
376
  const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic, {
377
+ connection,
370
378
  namespace,
371
379
  });
372
380
  if (await WorkflowService.isSideEffectAllowed(hotMeshClient, 'hook')) {
@@ -395,13 +403,14 @@ class WorkflowService {
395
403
  * @template T - the result type
396
404
  */
397
405
  static async once(fn, ...args) {
398
- const { COUNTER, namespace, workflowId, workflowTopic, workflowDimension, replay, } = WorkflowService.getContext();
406
+ const { COUNTER, connection, namespace, workflowId, workflowTopic, workflowDimension, replay, } = WorkflowService.getContext();
399
407
  const execIndex = COUNTER.counter = COUNTER.counter + 1;
400
408
  const sessionId = `-once${workflowDimension}-${execIndex}-`;
401
409
  if (sessionId in replay) {
402
410
  return serializer_1.SerializerService.fromString(replay[sessionId]).data;
403
411
  }
404
412
  const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic, {
413
+ connection,
405
414
  namespace,
406
415
  });
407
416
  const keyParams = {
@@ -424,8 +433,9 @@ class WorkflowService {
424
433
  * Interrupts a running job
425
434
  */
426
435
  static async interrupt(jobId, options = {}) {
427
- const { workflowTopic, namespace } = WorkflowService.getContext();
436
+ const { workflowTopic, connection, namespace, } = WorkflowService.getContext();
428
437
  const hotMeshClient = await worker_1.WorkerService.getHotMesh(workflowTopic, {
438
+ connection,
429
439
  namespace,
430
440
  });
431
441
  if (await WorkflowService.isSideEffectAllowed(hotMeshClient, 'interrupt')) {
@@ -88,6 +88,10 @@ type WorkflowContext = {
88
88
  * the native HotMesh message that encapsulates the arguments, metadata, and raw data for the workflow
89
89
  */
90
90
  raw: StreamData;
91
+ /**
92
+ * the HotMesh connection configuration (io/redis NPM package reference and login credentials)
93
+ */
94
+ connection: Connection;
91
95
  };
92
96
  /**
93
97
  * The schema for the full-text-search (RediSearch) index.
@@ -7,7 +7,7 @@ export { ActivityConfig, ActivityWorkflowDataType, ChildResponseType, ClientConf
7
7
  export { DurableChildErrorType, DurableProxyErrorType, DurableSleepErrorType, DurableWaitForAllErrorType, DurableWaitForErrorType, } from './error';
8
8
  export { ActivityAction, DependencyExport, DurableJobExport, ExportCycles, ExportItem, ExportOptions, ExportTransitions, JobAction, JobExport, JobActionExport, JobTimeline, } from './exporter';
9
9
  export { HookCondition, HookConditions, HookGate, HookInterface, HookRule, HookRules, HookSignal, } from './hook';
10
- export { ILogger } from './logger';
10
+ export { ILogger, LogLevel, } from './logger';
11
11
  export { ExtensionType, JobCompletionOptions, JobData, JobsData, JobInterruptOptions, JobMetadata, JobOutput, JobState, JobStatus, PartialJobState, } from './job';
12
12
  export { MappingStatements } from './map';
13
13
  export { Pipe, PipeContext, PipeItem, PipeItems, PipeObject, ReduceObject, } from './pipe';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -84,7 +84,6 @@
84
84
  "js-yaml": "^4.1.0",
85
85
  "ms": "^2.1.3",
86
86
  "nanoid": "^3.3.6",
87
- "systeminformation": "^5.22.2",
88
87
  "winston": "^3.8.2"
89
88
  },
90
89
  "devDependencies": {
package/types/durable.ts CHANGED
@@ -106,6 +106,11 @@ type WorkflowContext = {
106
106
  * the native HotMesh message that encapsulates the arguments, metadata, and raw data for the workflow
107
107
  */
108
108
  raw: StreamData;
109
+
110
+ /**
111
+ * the HotMesh connection configuration (io/redis NPM package reference and login credentials)
112
+ */
113
+ connection: Connection;
109
114
  };
110
115
 
111
116
  /**
package/types/index.ts CHANGED
@@ -77,7 +77,10 @@ export {
77
77
  HookRules,
78
78
  HookSignal,
79
79
  } from './hook';
80
- export { ILogger } from './logger';
80
+ export {
81
+ ILogger,
82
+ LogLevel,
83
+ } from './logger';
81
84
  export {
82
85
  ExtensionType,
83
86
  JobCompletionOptions,