@hotmeshio/hotmesh 0.0.37 → 0.0.39

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 (78) hide show
  1. package/README.md +14 -8
  2. package/build/modules/enums.d.ts +29 -23
  3. package/build/modules/enums.js +38 -29
  4. package/build/modules/errors.d.ts +1 -1
  5. package/build/modules/errors.js +9 -7
  6. package/build/modules/key.d.ts +1 -34
  7. package/build/modules/key.js +24 -47
  8. package/build/package.json +1 -1
  9. package/build/services/activities/activity.js +1 -1
  10. package/build/services/activities/hook.js +4 -9
  11. package/build/services/activities/trigger.d.ts +3 -2
  12. package/build/services/activities/trigger.js +10 -6
  13. package/build/services/durable/client.d.ts +9 -1
  14. package/build/services/durable/client.js +30 -14
  15. package/build/services/durable/handle.js +2 -2
  16. package/build/services/durable/worker.js +4 -3
  17. package/build/services/engine/index.d.ts +2 -1
  18. package/build/services/engine/index.js +6 -6
  19. package/build/services/hotmesh/index.d.ts +2 -2
  20. package/build/services/hotmesh/index.js +3 -4
  21. package/build/services/quorum/index.d.ts +6 -6
  22. package/build/services/quorum/index.js +47 -11
  23. package/build/services/router/index.js +16 -14
  24. package/build/services/store/clients/ioredis.d.ts +1 -0
  25. package/build/services/store/clients/ioredis.js +9 -0
  26. package/build/services/store/clients/redis.d.ts +1 -0
  27. package/build/services/store/clients/redis.js +16 -0
  28. package/build/services/store/index.d.ts +15 -9
  29. package/build/services/store/index.js +46 -23
  30. package/build/services/stream/clients/ioredis.d.ts +1 -0
  31. package/build/services/stream/clients/ioredis.js +33 -24
  32. package/build/services/stream/clients/redis.d.ts +1 -0
  33. package/build/services/stream/clients/redis.js +15 -0
  34. package/build/services/stream/index.d.ts +1 -0
  35. package/build/services/task/index.d.ts +10 -3
  36. package/build/services/task/index.js +35 -17
  37. package/build/services/worker/index.d.ts +1 -0
  38. package/build/services/worker/index.js +24 -0
  39. package/build/types/durable.d.ts +3 -2
  40. package/build/types/hotmesh.d.ts +43 -2
  41. package/build/types/hotmesh.js +28 -0
  42. package/build/types/index.d.ts +3 -2
  43. package/build/types/index.js +3 -1
  44. package/build/types/logger.d.ts +1 -0
  45. package/build/types/logger.js +1 -0
  46. package/build/types/quorum.d.ts +11 -1
  47. package/build/types/redisclient.d.ts +1 -0
  48. package/build/types/task.d.ts +1 -0
  49. package/build/types/task.js +2 -0
  50. package/modules/enums.ts +49 -35
  51. package/modules/errors.ts +17 -8
  52. package/modules/key.ts +3 -40
  53. package/package.json +1 -1
  54. package/services/activities/activity.ts +2 -2
  55. package/services/activities/hook.ts +18 -9
  56. package/services/activities/trigger.ts +10 -6
  57. package/services/durable/client.ts +31 -15
  58. package/services/durable/handle.ts +3 -3
  59. package/services/durable/worker.ts +4 -3
  60. package/services/engine/index.ts +13 -12
  61. package/services/hotmesh/index.ts +4 -5
  62. package/services/quorum/index.ts +48 -12
  63. package/services/router/index.ts +26 -24
  64. package/services/store/clients/ioredis.ts +9 -0
  65. package/services/store/clients/redis.ts +16 -0
  66. package/services/store/index.ts +63 -25
  67. package/services/stream/clients/ioredis.ts +33 -24
  68. package/services/stream/clients/redis.ts +14 -0
  69. package/services/stream/index.ts +1 -0
  70. package/services/task/index.ts +66 -24
  71. package/services/worker/index.ts +30 -0
  72. package/types/durable.ts +6 -5
  73. package/types/hotmesh.ts +47 -2
  74. package/types/index.ts +8 -1
  75. package/types/logger.ts +3 -1
  76. package/types/quorum.ts +15 -4
  77. package/types/redisclient.ts +1 -0
  78. package/types/task.ts +1 -0
@@ -25,18 +25,18 @@ class IORedisStreamService extends index_1.StreamService {
25
25
  try {
26
26
  return (await this.redisClient.xgroup(command, key, groupName, id, mkStream)) === 'OK';
27
27
  }
28
- catch (err) {
28
+ catch (error) {
29
29
  this.logger.info(`Consumer group not created with MKSTREAM for key: ${key} and group: ${groupName}`);
30
- throw err;
30
+ throw error;
31
31
  }
32
32
  }
33
33
  else {
34
34
  try {
35
35
  return (await this.redisClient.xgroup(command, key, groupName, id)) === 'OK';
36
36
  }
37
- catch (err) {
37
+ catch (error) {
38
38
  this.logger.info(`Consumer group not created for key: ${key} and group: ${groupName}`);
39
- throw err;
39
+ throw error;
40
40
  }
41
41
  }
42
42
  }
@@ -44,9 +44,9 @@ class IORedisStreamService extends index_1.StreamService {
44
44
  try {
45
45
  return await (multi || this.redisClient).xadd(key, id, messageId, messageValue);
46
46
  }
47
- catch (err) {
48
- this.logger.error(`Error publishing 'xadd'; key: ${key}`, err);
49
- throw err;
47
+ catch (error) {
48
+ this.logger.error(`Error publishing 'xadd'; key: ${key}`, { error });
49
+ throw error;
50
50
  }
51
51
  }
52
52
  async xreadgroup(command, groupName, consumerName, blockOption, blockTime, streamsOption, streamName, id) {
@@ -56,9 +56,9 @@ class IORedisStreamService extends index_1.StreamService {
56
56
  // @ts-ignore
57
57
  blockOption, blockTime, streamsOption, streamName, id);
58
58
  }
59
- catch (err) {
60
- this.logger.error(`Error reading stream data [Stream ${streamName}] [Group ${groupName}]`, err);
61
- throw err;
59
+ catch (error) {
60
+ this.logger.error(`Error reading stream data [Stream ${streamName}] [Group ${groupName}]`, { error });
61
+ throw error;
62
62
  }
63
63
  }
64
64
  async xpending(key, group, start, end, count, consumer) {
@@ -75,40 +75,49 @@ class IORedisStreamService extends index_1.StreamService {
75
75
  try {
76
76
  return await this.redisClient.call('XPENDING', ...args);
77
77
  }
78
- catch (err) {
79
- this.logger.error('err, args', err, args);
78
+ catch (error) {
79
+ this.logger.error('err, args', { error }, args);
80
80
  }
81
81
  }
82
- catch (err) {
83
- this.logger.error(`Error in retrieving pending messages for [stream ${key}], [group ${group}]`, err);
84
- throw err;
82
+ catch (error) {
83
+ this.logger.error(`Error in retrieving pending messages for [stream ${key}], [group ${group}]`, { error });
84
+ throw error;
85
85
  }
86
86
  }
87
87
  async xclaim(key, group, consumer, minIdleTime, id, ...args) {
88
88
  try {
89
89
  return await this.redisClient.xclaim(key, group, consumer, minIdleTime, id, ...args);
90
90
  }
91
- catch (err) {
92
- this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, err);
93
- throw err;
91
+ catch (error) {
92
+ this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { error });
93
+ throw error;
94
94
  }
95
95
  }
96
96
  async xack(key, group, id, multi) {
97
97
  try {
98
98
  return await (multi || this.redisClient).xack(key, group, id);
99
99
  }
100
- catch (err) {
101
- this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, err);
102
- throw err;
100
+ catch (error) {
101
+ this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { error });
102
+ throw error;
103
103
  }
104
104
  }
105
105
  async xdel(key, id, multi) {
106
106
  try {
107
107
  return await (multi || this.redisClient).xdel(key, id);
108
108
  }
109
- catch (err) {
110
- this.logger.error(`Error in deleting messages with id: ${id} for key: ${key}`, err);
111
- throw err;
109
+ catch (error) {
110
+ this.logger.error(`Error in deleting messages with id: ${id} for key: ${key}`, { error });
111
+ throw error;
112
+ }
113
+ }
114
+ async xlen(key, multi) {
115
+ try {
116
+ return await (multi || this.redisClient).xlen(key);
117
+ }
118
+ catch (error) {
119
+ this.logger.error(`Error getting stream depth: ${key}`, { error });
120
+ throw error;
112
121
  }
113
122
  }
114
123
  }
@@ -19,5 +19,6 @@ declare class RedisStreamService extends StreamService<RedisClientType, RedisMul
19
19
  xclaim(key: string, group: string, consumer: string, minIdleTime: number, id: string, ...args: string[]): Promise<ReclaimedMessageType>;
20
20
  xack(key: string, group: string, id: string, multi?: RedisMultiType): Promise<number | RedisMultiType>;
21
21
  xdel(key: string, id: string, multi?: RedisMultiType): Promise<number | RedisMultiType>;
22
+ xlen(key: string, multi?: RedisMultiType): Promise<number | RedisMultiType>;
22
23
  }
23
24
  export { RedisStreamService };
@@ -115,5 +115,20 @@ class RedisStreamService extends index_1.StreamService {
115
115
  throw err;
116
116
  }
117
117
  }
118
+ async xlen(key, multi) {
119
+ try {
120
+ if (multi) {
121
+ multi.XLEN(key);
122
+ return multi;
123
+ }
124
+ else {
125
+ return await this.redisClient.XLEN(key);
126
+ }
127
+ }
128
+ catch (error) {
129
+ this.logger.error(`Error getting stream depth: ${key}`, { error });
130
+ throw error;
131
+ }
132
+ }
118
133
  }
119
134
  exports.RedisStreamService = RedisStreamService;
@@ -17,5 +17,6 @@ declare abstract class StreamService<T, U> {
17
17
  abstract xclaim(key: string, group: string, consumer: string, minIdleTime: number, id: string, ...args: string[]): Promise<ReclaimedMessageType>;
18
18
  abstract xack(key: string, group: string, id: string, multi?: U): Promise<number | U>;
19
19
  abstract xdel(key: string, id: string, multi?: U): Promise<number | U>;
20
+ abstract xlen(key: string, multi?: U): Promise<number | U>;
20
21
  }
21
22
  export { StreamService };
@@ -4,6 +4,7 @@ import { StoreService } from '../store';
4
4
  import { HookInterface, HookRule } from '../../types/hook';
5
5
  import { JobCompletionOptions, JobState } from '../../types/job';
6
6
  import { RedisClient, RedisMulti } from '../../types/redis';
7
+ import { WorkListTaskType } from '../../types/task';
7
8
  declare class TaskService {
8
9
  store: StoreService<RedisClient, RedisMulti>;
9
10
  logger: ILogger;
@@ -13,12 +14,18 @@ declare class TaskService {
13
14
  processWebHooks(hookEventCallback: HookInterface): Promise<void>;
14
15
  enqueueWorkItems(keys: string[]): Promise<void>;
15
16
  registerJobForCleanup(jobId: string, inSeconds: number, options: JobCompletionOptions): Promise<void>;
16
- registerTimeHook(jobId: string, gId: string, activityId: string, type: 'sleep' | 'expire' | 'interrupt', inSeconds?: number, multi?: RedisMulti): Promise<void>;
17
+ registerTimeHook(jobId: string, gId: string, activityId: string, type: WorkListTaskType, inSeconds?: number, multi?: RedisMulti): Promise<void>;
17
18
  /**
18
- * Should this engine instance play the role of 'scout' for the quorum.
19
+ * Should this engine instance play the role of 'scout' on behalf
20
+ * of the entire quorum? The scout role is responsible for processing
21
+ * task lists on behalf of the collective.
19
22
  */
20
23
  shouldScout(): Promise<boolean>;
21
- processTimeHooks(timeEventCallback: (jobId: string, gId: string, activityId: string, type: 'sleep' | 'expire' | 'interrupt') => Promise<void>, listKey?: string): Promise<void>;
24
+ /**
25
+ * Callback handler that takes an item from a work list and
26
+ * processes according to its type
27
+ */
28
+ processTimeHooks(timeEventCallback: (jobId: string, gId: string, activityId: string, type: WorkListTaskType) => Promise<void>, listKey?: string): Promise<void>;
22
29
  cancelCleanup(): void;
23
30
  getHookRule(topic: string): Promise<HookRule | undefined>;
24
31
  registerWebHook(topic: string, context: JobState, dad: string, multi?: RedisMulti): Promise<string>;
@@ -4,6 +4,7 @@ exports.TaskService = void 0;
4
4
  const enums_1 = require("../../modules/enums");
5
5
  const utils_1 = require("../../modules/utils");
6
6
  const pipe_1 = require("../pipe");
7
+ const hotmesh_1 = require("../../types/hotmesh");
7
8
  class TaskService {
8
9
  constructor(store, logger) {
9
10
  this.cleanupTimeout = null;
@@ -31,19 +32,25 @@ class TaskService {
31
32
  async enqueueWorkItems(keys) {
32
33
  await this.store.addTaskQueues(keys);
33
34
  }
34
- async registerJobForCleanup(jobId, inSeconds = enums_1.EXPIRE_DURATION, options) {
35
+ async registerJobForCleanup(jobId, inSeconds = enums_1.HMSH_EXPIRE_DURATION, options) {
35
36
  if (inSeconds > 0) {
36
37
  await this.store.expireJob(jobId, inSeconds);
37
- const expireTimeSlot = Math.floor((Date.now() + (inSeconds * 1000)) / (enums_1.FIDELITY_SECONDS * 1000)) * (enums_1.FIDELITY_SECONDS * 1000); //n second awaken groups
38
- await this.store.registerExpireJob(jobId, expireTimeSlot, options);
38
+ const fromNow = Date.now() + (inSeconds * 1000);
39
+ const fidelityMS = enums_1.HMSH_FIDELITY_SECONDS * 1000;
40
+ const timeSlot = Math.floor(fromNow / fidelityMS) * fidelityMS;
41
+ await this.store.registerDependenciesForCleanup(jobId, timeSlot, options);
39
42
  }
40
43
  }
41
- async registerTimeHook(jobId, gId, activityId, type, inSeconds = enums_1.FIDELITY_SECONDS, multi) {
42
- const awakenTimeSlot = Math.floor((Date.now() + (inSeconds * 1000)) / (enums_1.FIDELITY_SECONDS * 1000)) * (enums_1.FIDELITY_SECONDS * 1000); //n second awaken groups
44
+ async registerTimeHook(jobId, gId, activityId, type, inSeconds = enums_1.HMSH_FIDELITY_SECONDS, multi) {
45
+ const fromNow = Date.now() + (inSeconds * 1000);
46
+ const fidelityMS = enums_1.HMSH_FIDELITY_SECONDS * 1000;
47
+ const awakenTimeSlot = Math.floor(fromNow / fidelityMS) * fidelityMS;
43
48
  await this.store.registerTimeHook(jobId, gId, activityId, type, awakenTimeSlot, multi);
44
49
  }
45
50
  /**
46
- * Should this engine instance play the role of 'scout' for the quorum.
51
+ * Should this engine instance play the role of 'scout' on behalf
52
+ * of the entire quorum? The scout role is responsible for processing
53
+ * task lists on behalf of the collective.
47
54
  */
48
55
  async shouldScout() {
49
56
  const wasScout = this.isScout;
@@ -52,31 +59,42 @@ class TaskService {
52
59
  if (!wasScout) {
53
60
  setTimeout(() => {
54
61
  this.isScout = false;
55
- }, enums_1.SCOUT_INTERVAL_SECONDS * 1000);
62
+ }, enums_1.HMSH_SCOUT_INTERVAL_SECONDS * 1000);
56
63
  }
57
64
  return true;
58
65
  }
59
66
  return false;
60
67
  }
68
+ /**
69
+ * Callback handler that takes an item from a work list and
70
+ * processes according to its type
71
+ */
61
72
  async processTimeHooks(timeEventCallback, listKey) {
62
73
  if (await this.shouldScout()) {
63
74
  try {
64
- const timeJob = await this.store.getNextTimeJob(listKey);
65
- if (Array.isArray(timeJob)) {
66
- //a queue had a job; try again immediately
67
- const [listKey, jobId, gId, activityId, type] = timeJob;
68
- await timeEventCallback(jobId, gId, activityId, type);
75
+ const workListTask = await this.store.getNextTask(listKey);
76
+ if (Array.isArray(workListTask)) {
77
+ const [listKey, target, gId, activityId, type] = workListTask;
78
+ if (type === 'delist') {
79
+ //delist the signalKey (target)
80
+ const key = this.store.mintKey(hotmesh_1.KeyType.SIGNALS, { appId: this.store.appId });
81
+ await this.store.redisClient[this.store.commands.hdel](key, target);
82
+ }
83
+ else {
84
+ //awaken/expire/interrupt
85
+ await timeEventCallback(target, gId, activityId, type);
86
+ }
69
87
  await (0, utils_1.sleepFor)(0);
70
88
  this.processTimeHooks(timeEventCallback, listKey);
71
89
  }
72
- else if (timeJob) {
73
- //a queue was just emptied; try again immediately
90
+ else if (workListTask) {
91
+ //a worklist was just emptied; try again immediately
74
92
  await (0, utils_1.sleepFor)(0);
75
93
  this.processTimeHooks(timeEventCallback);
76
94
  }
77
95
  else {
78
- //all queues are empty; sleep before checking
79
- let sleep = (0, utils_1.XSleepFor)(enums_1.FIDELITY_SECONDS * 1000);
96
+ //no worklists exist; sleep before checking
97
+ let sleep = (0, utils_1.XSleepFor)(enums_1.HMSH_FIDELITY_SECONDS * 1000);
80
98
  this.cleanupTimeout = sleep.timerId;
81
99
  await sleep.promise;
82
100
  this.processTimeHooks(timeEventCallback);
@@ -89,7 +107,7 @@ class TaskService {
89
107
  }
90
108
  else {
91
109
  //didn't get the scout role; try again in 'one-ish' minutes
92
- let sleep = (0, utils_1.XSleepFor)(enums_1.SCOUT_INTERVAL_SECONDS * 1000 * 2 * Math.random());
110
+ let sleep = (0, utils_1.XSleepFor)(enums_1.HMSH_SCOUT_INTERVAL_SECONDS * 1000 * 2 * Math.random());
93
111
  this.cleanupTimeout = sleep.timerId;
94
112
  await sleep.promise;
95
113
  this.processTimeHooks(timeEventCallback);
@@ -25,6 +25,7 @@ declare class WorkerService {
25
25
  initStreamChannel(service: WorkerService, stream: RedisClient): Promise<void>;
26
26
  initRouter(worker: HotMeshWorker, logger: ILogger): Router;
27
27
  subscriptionHandler(): SubscriptionCallback;
28
+ sayPong(appId: string, guid: string, originator: string, details?: boolean): Promise<void>;
28
29
  throttle(delayInMillis: number): Promise<void>;
29
30
  }
30
31
  export { WorkerService };
@@ -96,8 +96,32 @@ class WorkerService {
96
96
  if (message.type === 'throttle') {
97
97
  self.throttle(message.throttle);
98
98
  }
99
+ else if (message.type === 'ping') {
100
+ self.sayPong(self.appId, self.guid, message.originator, message.details);
101
+ }
99
102
  };
100
103
  }
104
+ async sayPong(appId, guid, originator, details = false) {
105
+ let profile;
106
+ if (details) {
107
+ const params = {
108
+ appId: this.appId,
109
+ topic: this.topic,
110
+ };
111
+ profile = {
112
+ engine_id: this.guid,
113
+ namespace: this.namespace,
114
+ app_id: this.appId,
115
+ worker_topic: this.topic,
116
+ stream: this.stream.mintKey(key_1.KeyType.STREAMS, params),
117
+ };
118
+ }
119
+ this.store.publish(key_1.KeyType.QUORUM, {
120
+ type: 'pong',
121
+ guid, originator,
122
+ profile,
123
+ }, appId);
124
+ }
101
125
  async throttle(delayInMillis) {
102
126
  this.router.setThrottle(delayInMillis);
103
127
  }
@@ -1,3 +1,4 @@
1
+ import { LogLevel } from './logger';
1
2
  import { RedisClass, RedisOptions } from './redis';
2
3
  type WorkflowConfig = {
3
4
  backoffCoefficient?: number;
@@ -151,12 +152,12 @@ type MeshOSActivityOptions = {
151
152
  type MeshOSWorkerOptions = {
152
153
  taskQueue?: string;
153
154
  allowList?: Array<MeshOSOptions | string>;
154
- logLevel?: string;
155
+ logLevel?: LogLevel;
155
156
  maxSystemRetries?: number;
156
157
  backoffCoefficient?: number;
157
158
  };
158
159
  type WorkerOptions = {
159
- logLevel?: string;
160
+ logLevel?: LogLevel;
160
161
  maxSystemRetries?: number;
161
162
  backoffCoefficient?: number;
162
163
  };
@@ -3,6 +3,47 @@ import { HotMeshService } from '../services/hotmesh';
3
3
  import { HookRules } from './hook';
4
4
  import { RedisClass, RedisClient, RedisOptions } from './redis';
5
5
  import { StreamData, StreamDataResponse } from './stream';
6
+ import { LogLevel } from './logger';
7
+ /**
8
+ * the full set of entity types that are stored in the key/value store
9
+ */
10
+ declare enum KeyType {
11
+ APP = "APP",
12
+ ENGINE_ID = "ENGINE",
13
+ HOOKS = "HOOKS",
14
+ JOB_DEPENDENTS = "JOB_DEPENDENTS",
15
+ JOB_STATE = "JOB_STATE",
16
+ JOB_STATS_GENERAL = "JOB_STATS_GENERAL",
17
+ JOB_STATS_MEDIAN = "JOB_STATS_MEDIAN",
18
+ JOB_STATS_INDEX = "JOB_STATS_INDEX",
19
+ HOTMESH = "HOTMESH",
20
+ QUORUM = "QUORUM",
21
+ SCHEMAS = "SCHEMAS",
22
+ SIGNALS = "SIGNALS",
23
+ STREAMS = "STREAMS",
24
+ SUBSCRIPTIONS = "SUBSCRIPTIONS",
25
+ SUBSCRIPTION_PATTERNS = "SUBSCRIPTION_PATTERNS",
26
+ SYMKEYS = "SYMKEYS",
27
+ SYMVALS = "SYMVALS",
28
+ TIME_RANGE = "TIME_RANGE",
29
+ WORK_ITEMS = "WORK_ITEMS"
30
+ }
31
+ /**
32
+ * minting keys, requires one or more of the following parameters
33
+ */
34
+ type KeyStoreParams = {
35
+ appId?: string;
36
+ engineId?: string;
37
+ appVersion?: string;
38
+ jobId?: string;
39
+ activityId?: string;
40
+ jobKey?: string;
41
+ dateTime?: string;
42
+ facet?: string;
43
+ topic?: string;
44
+ timeValue?: number;
45
+ scoutType?: 'signal' | 'time';
46
+ };
6
47
  type HotMesh = typeof HotMeshService;
7
48
  type RedisConfig = {
8
49
  class: RedisClass;
@@ -34,7 +75,7 @@ type HotMeshConfig = {
34
75
  namespace?: string;
35
76
  name?: string;
36
77
  logger?: ILogger;
37
- logLevel?: 'silly' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
78
+ logLevel?: LogLevel;
38
79
  engine?: HotMeshEngine;
39
80
  workers?: HotMeshWorker[];
40
81
  };
@@ -79,4 +120,4 @@ type HotMeshApps = {
79
120
  export { HotMesh, HotMeshEngine, RedisConfig, HotMeshWorker, HotMeshSettings, HotMeshApp, //a single app in the db
80
121
  HotMeshApps, //object array of all apps in the db
81
122
  HotMeshConfig, //customer config
82
- HotMeshManifest, HotMeshGraph };
123
+ HotMeshManifest, HotMeshGraph, KeyType, KeyStoreParams, };
@@ -1,2 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KeyType = void 0;
4
+ /**
5
+ * the full set of entity types that are stored in the key/value store
6
+ */
7
+ var KeyType;
8
+ (function (KeyType) {
9
+ KeyType["APP"] = "APP";
10
+ KeyType["ENGINE_ID"] = "ENGINE";
11
+ KeyType["HOOKS"] = "HOOKS";
12
+ KeyType["JOB_DEPENDENTS"] = "JOB_DEPENDENTS";
13
+ KeyType["JOB_STATE"] = "JOB_STATE";
14
+ KeyType["JOB_STATS_GENERAL"] = "JOB_STATS_GENERAL";
15
+ KeyType["JOB_STATS_MEDIAN"] = "JOB_STATS_MEDIAN";
16
+ KeyType["JOB_STATS_INDEX"] = "JOB_STATS_INDEX";
17
+ KeyType["HOTMESH"] = "HOTMESH";
18
+ KeyType["QUORUM"] = "QUORUM";
19
+ KeyType["SCHEMAS"] = "SCHEMAS";
20
+ KeyType["SIGNALS"] = "SIGNALS";
21
+ KeyType["STREAMS"] = "STREAMS";
22
+ KeyType["SUBSCRIPTIONS"] = "SUBSCRIPTIONS";
23
+ KeyType["SUBSCRIPTION_PATTERNS"] = "SUBSCRIPTION_PATTERNS";
24
+ KeyType["SYMKEYS"] = "SYMKEYS";
25
+ KeyType["SYMVALS"] = "SYMVALS";
26
+ KeyType["TIME_RANGE"] = "TIME_RANGE";
27
+ KeyType["WORK_ITEMS"] = "WORK_ITEMS";
28
+ })(KeyType || (KeyType = {}));
29
+ exports.KeyType = KeyType;
30
+ ;
@@ -10,12 +10,13 @@ export { ILogger } from './logger';
10
10
  export { JobData, JobsData, JobMetadata, JobOutput, JobState, JobStatus, PartialJobState } from './job';
11
11
  export { MappingStatements } from './map';
12
12
  export { Pipe, PipeItem, PipeItems } from './pipe';
13
- export { HotMesh, HotMeshApp, HotMeshApps, HotMeshConfig, HotMeshEngine, RedisConfig, HotMeshGraph, HotMeshManifest, HotMeshSettings, HotMeshWorker } from './hotmesh';
14
- export { ActivateMessage, JobMessage, JobMessageCallback, PingMessage, PongMessage, QuorumMessage, SubscriptionCallback, ThrottleMessage, WorkMessage } from './quorum';
13
+ export { HotMesh, HotMeshApp, HotMeshApps, HotMeshConfig, HotMeshEngine, RedisConfig, HotMeshGraph, HotMeshManifest, HotMeshSettings, HotMeshWorker, KeyStoreParams, KeyType } from './hotmesh';
14
+ export { ActivateMessage, JobMessage, JobMessageCallback, PingMessage, PongMessage, QuorumMessage, QuorumMessageCallback, QuorumProfile, SubscriptionCallback, ThrottleMessage, WorkMessage } from './quorum';
15
15
  export { MultiResponseFlags, RedisClient, RedisMulti } from './redis';
16
16
  export { RedisClientType, RedisMultiType } from './redisclient';
17
17
  export { JSONSchema, StringAnyType, StringScalarType, StringStringType, SymbolMap, SymbolMaps, SymbolRanges, Symbols, SymbolSets } from './serializer';
18
18
  export { AggregatedData, CountByFacet, GetStatsOptions, IdsData, Measure, MeasureIds, MetricTypes, StatType, StatsType, IdsResponse, JobStats, JobStatsInput, JobStatsRange, StatsResponse, Segment, TimeSegment } from './stats';
19
19
  export { ReclaimedMessageType, StreamCode, StreamConfig, StreamData, StreamDataType, StreamError, StreamDataResponse, StreamRetryPolicy, StreamRole, StreamStatus } from './stream';
20
20
  export { context, Context, Counter, Meter, metrics, propagation, SpanContext, Span, SpanStatus, SpanStatusCode, SpanKind, trace, Tracer, ValueType } from './telemetry';
21
+ export { WorkListTaskType } from './task';
21
22
  export { TransitionMatch, TransitionRule, Transitions } from './transition';
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ValueType = exports.trace = exports.SpanKind = exports.SpanStatusCode = exports.propagation = exports.metrics = exports.context = exports.StreamStatus = exports.StreamRole = exports.StreamDataType = exports.IORedisClientType = exports.HookGate = exports.CollationFaultType = void 0;
3
+ exports.ValueType = exports.trace = exports.SpanKind = exports.SpanStatusCode = exports.propagation = exports.metrics = exports.context = exports.StreamStatus = exports.StreamRole = exports.StreamDataType = exports.KeyType = exports.IORedisClientType = exports.HookGate = exports.CollationFaultType = void 0;
4
4
  var collator_1 = require("./collator");
5
5
  Object.defineProperty(exports, "CollationFaultType", { enumerable: true, get: function () { return collator_1.CollationFaultType; } });
6
6
  var hook_1 = require("./hook");
7
7
  Object.defineProperty(exports, "HookGate", { enumerable: true, get: function () { return hook_1.HookGate; } });
8
8
  var ioredisclient_1 = require("./ioredisclient");
9
9
  Object.defineProperty(exports, "IORedisClientType", { enumerable: true, get: function () { return ioredisclient_1.RedisClientType; } });
10
+ var hotmesh_1 = require("./hotmesh");
11
+ Object.defineProperty(exports, "KeyType", { enumerable: true, get: function () { return hotmesh_1.KeyType; } });
10
12
  var stream_1 = require("./stream");
11
13
  Object.defineProperty(exports, "StreamDataType", { enumerable: true, get: function () { return stream_1.StreamDataType; } });
12
14
  Object.defineProperty(exports, "StreamRole", { enumerable: true, get: function () { return stream_1.StreamRole; } });
@@ -4,3 +4,4 @@ export interface ILogger {
4
4
  warn(message: string, ...meta: any[]): void;
5
5
  debug(message: string, ...meta: any[]): void;
6
6
  }
7
+ export type LogLevel = 'silly' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
@@ -1,2 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ ;
@@ -1,7 +1,16 @@
1
1
  import { JobOutput } from "./job";
2
+ export interface QuorumProfile {
3
+ namespace: string;
4
+ app_id: string;
5
+ engine_id: string;
6
+ worker_topic?: string;
7
+ stream?: string;
8
+ stream_depth?: number;
9
+ }
2
10
  export interface PingMessage {
3
11
  type: 'ping';
4
12
  originator: string;
13
+ details?: boolean;
5
14
  }
6
15
  export interface WorkMessage {
7
16
  type: 'work';
@@ -13,8 +22,9 @@ export interface CronMessage {
13
22
  }
14
23
  export interface PongMessage {
15
24
  type: 'pong';
16
- originator: string;
17
25
  guid: string;
26
+ originator: string;
27
+ profile?: QuorumProfile;
18
28
  }
19
29
  export interface ActivateMessage {
20
30
  type: 'activate';
@@ -4,6 +4,7 @@ interface RedisMultiType {
4
4
  XADD(key: string, id: string, fields: any): this;
5
5
  XACK(key: string, group: string, id: string): this;
6
6
  XDEL(key: string, id: string): this;
7
+ XLEN(key: string): this;
7
8
  HDEL(key: string, itemId: string): this;
8
9
  HGET(key: string, itemId: string): this;
9
10
  HGETALL(key: string): this;
@@ -0,0 +1 @@
1
+ export type WorkListTaskType = 'sleep' | 'expire' | 'interrupt' | 'delist';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/modules/enums.ts CHANGED
@@ -1,35 +1,49 @@
1
- // Engine Constants
2
- export const STATUS_CODE_SUCCESS = 200;
3
- export const STATUS_CODE_PENDING = 202;
4
- export const STATUS_CODE_TIMEOUT = 504;
5
- export const STATUS_CODE_INTERRUPT = 410;
6
- export const OTT_WAIT_TIME = 1000;
7
-
8
- // Stream Constants
9
- export const MAX_RETRIES = 3; //local retry; 10, 100, 1000ms
10
- export const MAX_TIMEOUT_MS = 60000;
11
- export const GRADUATED_INTERVAL_MS = 5000;
12
-
13
- export const BLOCK_DURATION = 15000; //Set to `15` so SIGINT/SIGTERM can interrupt; set to `0` to BLOCK indefinitely
14
- export const TEST_BLOCK_DURATION = 1000; //Set to `1000` so tests can interrupt quickly
15
- export const BLOCK_TIME_MS = process.env.NODE_ENV === 'test' ? TEST_BLOCK_DURATION : BLOCK_DURATION;
16
-
17
- export const XCLAIM_DELAY_MS = 1000 * 60; //max time a message can be unacked before it is claimed by another
18
- export const XCLAIM_COUNT = 3; //max number of times a message can be claimed by another before it is dead-lettered
19
- export const XPENDING_COUNT = 10;
20
-
21
- export const STATUS_CODE_UNACKED = 999;
22
- export const STATUS_CODE_UNKNOWN = 500;
23
- export const STATUS_MESSAGE_UNKNOWN = 'unknown';
24
-
25
- // HotMesh Constants
26
- export const EXPIRE_DURATION = 15; // default expire in seconds; once job state semaphore reaches '0', this is applied to set Redis to expire the job HASH
27
- export const BASE_FIDELITY_SECONDS = 15; // granularity resolution window size
28
- export const TEST_FIDELITY_SECONDS = 5;
29
- export const FIDELITY_SECONDS = process.env.NODE_ENV === 'test' ? TEST_FIDELITY_SECONDS : BASE_FIDELITY_SECONDS
30
-
31
- // DURABLE CONSTANTS
32
- export const DURABLE_EXPIRE_SECONDS = 1;
33
-
34
- // TASK CONSTANTS
35
- export const SCOUT_INTERVAL_SECONDS = 60;
1
+ import { LogLevel } from "../types/logger";
2
+
3
+ // HOTMESH SYSTEM
4
+ export const HMSH_LOGLEVEL = process.env.HMSH_LOGLEVEL as LogLevel || 'info';
5
+
6
+ // STATUS CODES AND MESSAGES
7
+ export const HMSH_CODE_SUCCESS = 200;
8
+ export const HMSH_CODE_PENDING = 202;
9
+ export const HMSH_CODE_NOTFOUND = 404;
10
+ export const HMSH_CODE_INTERRUPT = 410;
11
+ export const HMSH_CODE_UNKNOWN = 500;
12
+ export const HMSH_CODE_TIMEOUT = 504;
13
+ export const HMSH_CODE_UNACKED = 999;
14
+
15
+ export const HMSH_CODE_DURABLE_SLEEPFOR = 592;
16
+ export const HMSH_CODE_DURABLE_INCOMPLETE = 593;
17
+ export const HMSH_CODE_DURABLE_WAITFOR = 594;
18
+ export const HMSH_CODE_DURABLE_TIMEOUT = 596;
19
+ export const HMSH_CODE_DURABLE_MAXED = 597;
20
+ export const HMSH_CODE_DURABLE_FATAL = 598;
21
+ export const HMSH_CODE_DURABLE_RETRYABLE = 599;
22
+
23
+ export const HMSH_STATUS_UNKNOWN = 'unknown';
24
+
25
+ // ENGINE
26
+ export const HMSH_OTT_WAIT_TIME = parseInt(process.env.HMSH_OTT_WAIT_TIME, 10) || 1000;
27
+ export const HMSH_EXPIRE_JOB_SECONDS = parseInt(process.env.HMSH_EXPIRE_JOB_SECONDS, 10) || 1;
28
+
29
+ // STREAM ROUTER
30
+ export const HMSH_MAX_RETRIES = parseInt(process.env.HMSH_MAX_RETRIES, 10) || 3;
31
+ export const HMSH_MAX_TIMEOUT_MS = parseInt(process.env.HMSH_MAX_TIMEOUT_MS, 10) || 60000;
32
+ export const HMSH_GRADUATED_INTERVAL_MS = parseInt(process.env.HMSH_GRADUATED_INTERVAL_MS, 10) || 5000;
33
+
34
+ const BASE_BLOCK_DURATION = 10000; // Modified for clarity
35
+ const TEST_BLOCK_DURATION = 1000; // Modified for clarity
36
+ export const HMSH_BLOCK_TIME_MS = process.env.HMSH_BLOCK_TIME_MS ? parseInt(process.env.HMSH_BLOCK_TIME_MS, 10) : (process.env.NODE_ENV === 'test' ? TEST_BLOCK_DURATION : BASE_BLOCK_DURATION);
37
+
38
+ export const HMSH_XCLAIM_DELAY_MS = parseInt(process.env.HMSH_XCLAIM_DELAY_MS, 10) || 1000 * 60;
39
+ export const HMSH_XCLAIM_COUNT = parseInt(process.env.HMSH_XCLAIM_COUNT, 10) || 3;
40
+ export const HMSH_XPENDING_COUNT = parseInt(process.env.HMSH_XPENDING_COUNT, 10) || 10;
41
+
42
+ // TASK WORKER
43
+ export const HMSH_EXPIRE_DURATION = parseInt(process.env.HMSH_EXPIRE_DURATION, 10) || 1;
44
+
45
+ const BASE_FIDELITY_SECONDS = 5;
46
+ const TEST_FIDELITY_SECONDS = 5;
47
+ export const HMSH_FIDELITY_SECONDS = process.env.HMSH_FIDELITY_SECONDS ? parseInt(process.env.HMSH_FIDELITY_SECONDS, 10) : (process.env.NODE_ENV === 'test' ? TEST_FIDELITY_SECONDS : BASE_FIDELITY_SECONDS);
48
+
49
+ export const HMSH_SCOUT_INTERVAL_SECONDS = parseInt(process.env.HMSH_SCOUT_INTERVAL_SECONDS, 10) || 60;