@hotmeshio/hotmesh 0.2.3 → 0.2.4

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -92,6 +92,7 @@ class EngineService {
92
92
  reclaimDelay: config.engine.reclaimDelay,
93
93
  reclaimCount: config.engine.reclaimCount,
94
94
  throttle,
95
+ readonly: config.engine.readonly,
95
96
  }, this.stream, this.store, this.logger);
96
97
  }
97
98
  async fetchAndVerifyVID(vid, count = 0) {
@@ -1,21 +1,21 @@
1
1
  import { HotMesh } from '../hotmesh';
2
- import { MeshCallConnectParams, MeshCallCronParams, MeshCallExecParams, MeshCallFlushParams, MeshCallInterruptParams } from '../../types/meshcall';
2
+ import { MeshCallConnectParams, MeshCallCronParams, MeshCallExecParams, MeshCallFlushParams, MeshCallInstanceOptions, MeshCallInterruptParams } from '../../types/meshcall';
3
3
  import { RedisConfig } from '../../types';
4
4
  declare class MeshCall {
5
5
  static workers: Map<string, HotMesh | Promise<HotMesh>>;
6
6
  static engines: Map<string, HotMesh | Promise<HotMesh>>;
7
7
  static connections: Map<string, any>;
8
8
  constructor();
9
- static findFirstMatching(workers: Map<string, HotMesh | Promise<HotMesh>>, namespace: string, config: RedisConfig): Promise<HotMesh | void>;
10
- static getHotMeshClient: (namespace: string, connection: RedisConfig) => Promise<HotMesh>;
9
+ static findFirstMatching(targets: Map<string, HotMesh | Promise<HotMesh>>, namespace: string, config: RedisConfig, options?: MeshCallInstanceOptions): Promise<HotMesh | void>;
10
+ static getHotMeshClient: (namespace: string, connection: RedisConfig, options?: MeshCallInstanceOptions) => Promise<HotMesh>;
11
11
  static verifyWorkflowActive(hotMesh: HotMesh, appId?: string, count?: number): Promise<boolean>;
12
12
  static activateWorkflow(hotMesh: HotMesh, appId?: string, version?: string): Promise<void>;
13
- static getInstance(namespace: string, redis: RedisConfig): Promise<HotMesh>;
13
+ static getInstance(namespace: string, redis: RedisConfig, options?: MeshCallInstanceOptions): Promise<HotMesh>;
14
14
  static connect(params: MeshCallConnectParams): Promise<HotMesh>;
15
15
  static exec<U>(params: MeshCallExecParams): Promise<U>;
16
16
  static flush(params: MeshCallFlushParams): Promise<void>;
17
17
  static cron(params: MeshCallCronParams): Promise<boolean>;
18
- static interrupt(params: MeshCallInterruptParams): Promise<void>;
18
+ static interrupt(params: MeshCallInterruptParams): Promise<boolean>;
19
19
  static shutdown(): Promise<void>;
20
20
  }
21
21
  export { MeshCall };
@@ -14,11 +14,15 @@ const cron_1 = require("../pipe/functions/cron");
14
14
  const factory_1 = require("./schemas/factory");
15
15
  class MeshCall {
16
16
  constructor() { }
17
- static async findFirstMatching(workers, namespace = key_1.HMNS, config) {
18
- for (const [id, hotMeshInstance] of workers) {
19
- if ((await hotMeshInstance).namespace === namespace) {
17
+ static async findFirstMatching(targets, namespace = key_1.HMNS, config, options = {}) {
18
+ for (const [id, hotMeshInstance] of targets) {
19
+ const hotMesh = await hotMeshInstance;
20
+ const appId = hotMesh.engine.appId;
21
+ if (appId === namespace) {
20
22
  if (id.startsWith((0, utils_1.hashOptions)(config.options))) {
21
- return hotMeshInstance;
23
+ if (Boolean(options.readonly) == Boolean(hotMesh.engine.router.readonly)) {
24
+ return hotMeshInstance;
25
+ }
22
26
  }
23
27
  }
24
28
  }
@@ -60,12 +64,15 @@ class MeshCall {
60
64
  }
61
65
  }
62
66
  }
63
- static async getInstance(namespace, redis) {
64
- let hotMeshInstance = await MeshCall.findFirstMatching(MeshCall.workers, namespace, redis);
67
+ static async getInstance(namespace, redis, options = {}) {
68
+ let hotMeshInstance;
69
+ if (!options.readonly) {
70
+ hotMeshInstance = await MeshCall.findFirstMatching(MeshCall.workers, namespace, redis, options);
71
+ }
65
72
  if (!hotMeshInstance) {
66
- hotMeshInstance = await MeshCall.findFirstMatching(MeshCall.engines, namespace, redis);
73
+ hotMeshInstance = await MeshCall.findFirstMatching(MeshCall.engines, namespace, redis, options);
67
74
  if (!hotMeshInstance) {
68
- hotMeshInstance = (await MeshCall.getHotMeshClient(namespace, redis));
75
+ hotMeshInstance = (await MeshCall.getHotMeshClient(namespace, redis, options));
69
76
  }
70
77
  }
71
78
  return hotMeshInstance;
@@ -131,7 +138,7 @@ class MeshCall {
131
138
  await hotMeshInstance.scrub(params.id ?? params?.options?.id);
132
139
  }
133
140
  static async cron(params) {
134
- try {
141
+ if (params.callback) {
135
142
  await MeshCall.connect({
136
143
  logLevel: params.logLevel,
137
144
  guid: params.guid,
@@ -140,22 +147,26 @@ class MeshCall {
140
147
  callback: params.callback,
141
148
  namespace: params.namespace,
142
149
  });
143
- const TOPIC = `${params.namespace ?? key_1.HMNS}.cron`;
144
- let delay = params.options.delay
150
+ }
151
+ const TOPIC = `${params.namespace ?? key_1.HMNS}.cron`;
152
+ const maxCycles = params.options.maxCycles ?? 100000;
153
+ let interval = enums_1.HMSH_FIDELITY_SECONDS;
154
+ let delay;
155
+ let cron;
156
+ if ((0, utils_1.isValidCron)(params.options.interval)) {
157
+ cron = params.options.interval;
158
+ const nextDelay = new cron_1.CronHandler().nextDelay(cron);
159
+ delay = nextDelay > 0 ? nextDelay : undefined;
160
+ }
161
+ else {
162
+ const seconds = (0, ms_1.default)(params.options.interval) / 1000;
163
+ interval = Math.max(seconds, enums_1.HMSH_FIDELITY_SECONDS);
164
+ delay = params.options.delay
145
165
  ? (0, ms_1.default)(params.options.delay) / 1000
146
166
  : undefined;
147
- let cron;
148
- let interval = enums_1.HMSH_FIDELITY_SECONDS;
149
- if ((0, utils_1.isValidCron)(params.options.interval)) {
150
- cron = params.options.interval;
151
- delay = Math.max(new cron_1.CronHandler().nextDelay(cron), 0);
152
- }
153
- else {
154
- const seconds = (0, ms_1.default)(params.options.interval) / 1000;
155
- interval = Math.max(seconds, enums_1.HMSH_FIDELITY_SECONDS);
156
- }
157
- const maxCycles = params.options.maxCycles ?? 1000000;
158
- const hotMeshInstance = await MeshCall.getInstance(params.namespace, params.redis);
167
+ }
168
+ try {
169
+ const hotMeshInstance = await MeshCall.getInstance(params.namespace, params.redis, { readonly: params.callback ? false : true, guid: params.guid });
159
170
  await hotMeshInstance.pub(TOPIC, {
160
171
  id: params.options.id,
161
172
  topic: params.topic,
@@ -176,7 +187,13 @@ class MeshCall {
176
187
  }
177
188
  static async interrupt(params) {
178
189
  const hotMeshInstance = await MeshCall.getInstance(params.namespace, params.redis);
179
- await hotMeshInstance.interrupt(`${params.namespace ?? key_1.HMNS}.cron`, params.options.id, { throw: false, expire: 60 });
190
+ try {
191
+ await hotMeshInstance.interrupt(`${params.namespace ?? key_1.HMNS}.cron`, params.options.id, { throw: false, expire: 1 });
192
+ }
193
+ catch (error) {
194
+ return false;
195
+ }
196
+ return true;
180
197
  }
181
198
  static async shutdown() {
182
199
  for (const [_, hotMeshInstance] of MeshCall.workers) {
@@ -193,7 +210,7 @@ _a = MeshCall;
193
210
  MeshCall.workers = new Map();
194
211
  MeshCall.engines = new Map();
195
212
  MeshCall.connections = new Map();
196
- MeshCall.getHotMeshClient = async (namespace, connection) => {
213
+ MeshCall.getHotMeshClient = async (namespace, connection, options = {}) => {
197
214
  const optionsHash = (0, utils_1.hashOptions)(connection.options);
198
215
  const targetNS = namespace ?? key_1.HMNS;
199
216
  const connectionNS = `${optionsHash}.${targetNS}`;
@@ -203,6 +220,7 @@ MeshCall.getHotMeshClient = async (namespace, connection) => {
203
220
  return hotMeshClient;
204
221
  }
205
222
  const hotMeshClient = hotmesh_1.HotMesh.init({
223
+ guid: options.guid,
206
224
  appId: targetNS,
207
225
  logLevel: enums_1.HMSH_LOGLEVEL,
208
226
  engine: {
@@ -210,6 +228,7 @@ MeshCall.getHotMeshClient = async (namespace, connection) => {
210
228
  class: connection.class,
211
229
  options: connection.options,
212
230
  },
231
+ readonly: options.readonly,
213
232
  },
214
233
  });
215
234
  MeshCall.engines.set(connectionNS, hotMeshClient);
@@ -72,8 +72,6 @@ const getWorkflowYAML = (appId = key_1.HMNS, version = exports.VERSION) => {
72
72
 
73
73
  - subscribes: ${appId}.cron
74
74
 
75
- expire: 120
76
-
77
75
  input:
78
76
  schema:
79
77
  type: object
@@ -123,6 +121,8 @@ const getWorkflowYAML = (appId = key_1.HMNS, version = exports.VERSION) => {
123
121
  properties:
124
122
  sleepSeconds:
125
123
  type: number
124
+ iterationCount:
125
+ type: number
126
126
  maps:
127
127
  sleepSeconds:
128
128
  '@pipe':
@@ -74,8 +74,10 @@ class Router {
74
74
  });
75
75
  }
76
76
  async consumeMessages(stream, group, consumer, callback) {
77
- if (this.readonly)
77
+ if (this.readonly) {
78
+ this.logger.info(`router-stream-readonly`, { group, consumer, stream });
78
79
  return;
80
+ }
79
81
  this.logger.info(`router-stream-starting`, { group, consumer, stream });
80
82
  Router.instances.add(this);
81
83
  this.shouldConsume = true;
@@ -46,13 +46,17 @@ interface MeshCallCronParams {
46
46
  topic: string;
47
47
  redis: RedisConfig;
48
48
  args: any[];
49
- callback: (...args: any[]) => any;
49
+ callback?: (...args: any[]) => any;
50
50
  options: MeshCallCronOptions;
51
51
  }
52
+ interface MeshCallInstanceOptions {
53
+ readonly?: boolean;
54
+ guid?: string;
55
+ }
52
56
  interface MeshCallInterruptParams {
53
57
  namespace?: string;
54
58
  topic: string;
55
59
  redis: RedisConfig;
56
60
  options: MeshCallInterruptOptions;
57
61
  }
58
- export { MeshCallConnectParams, MeshCallExecParams, MeshCallCronParams, MeshCallExecOptions, MeshCallCronOptions, MeshCallInterruptOptions, MeshCallInterruptParams, MeshCallFlushOptions, MeshCallFlushParams, };
62
+ export { MeshCallConnectParams, MeshCallExecParams, MeshCallCronParams, MeshCallExecOptions, MeshCallCronOptions, MeshCallInterruptOptions, MeshCallInterruptParams, MeshCallFlushOptions, MeshCallFlushParams, MeshCallInstanceOptions, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
package/types/meshcall.ts CHANGED
@@ -153,15 +153,31 @@ interface MeshCallCronParams {
153
153
  */
154
154
  args: any[];
155
155
  /**
156
- * linked worker function to run
156
+ * linked worker function to run; if not provided, the system will
157
+ * attempt to start the cron job using the topic, but a new
158
+ * worker will not be created. This is useful for spawning a cron job
159
+ * from an ephemeral node process.
157
160
  */
158
- callback: (...args: any[]) => any;
161
+ callback?: (...args: any[]) => any;
159
162
  /**
160
163
  * Options for the cron job
161
164
  */
162
165
  options: MeshCallCronOptions;
163
166
  }
164
167
 
168
+ interface MeshCallInstanceOptions {
169
+ /**
170
+ * if true, the connection to HotMesh will be in readonly mode
171
+ * and the instantiated client will not route messages
172
+ * @default false
173
+ */
174
+ readonly?: boolean;
175
+ /**
176
+ * Idempotent GUID for the worker and engine
177
+ */
178
+ guid?: string;
179
+ }
180
+
165
181
  interface MeshCallInterruptParams {
166
182
  /**
167
183
  * namespace for grouping common functions
@@ -191,4 +207,5 @@ export {
191
207
  MeshCallInterruptParams,
192
208
  MeshCallFlushOptions,
193
209
  MeshCallFlushParams,
210
+ MeshCallInstanceOptions,
194
211
  };