@hatchet-dev/typescript-sdk 1.0.0-alpha1 → 1.0.0-alpha2

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 (168) hide show
  1. package/clients/admin/admin-client.d.ts +15 -20
  2. package/clients/admin/admin-client.js +21 -17
  3. package/clients/hatchet-client/hatchet-client.d.ts +5 -4
  4. package/clients/hatchet-client/hatchet-client.js +6 -4
  5. package/clients/listeners/durable-listener/durable-listener-client.d.ts +25 -0
  6. package/clients/listeners/durable-listener/durable-listener-client.js +30 -0
  7. package/clients/listeners/durable-listener/pooled-durable-listener-client.d.ts +43 -0
  8. package/clients/listeners/durable-listener/pooled-durable-listener-client.js +241 -0
  9. package/clients/{listener/listener-client.d.ts → listeners/run-listener/child-listener-client.d.ts} +8 -8
  10. package/clients/{listener/listener-client.js → listeners/run-listener/child-listener-client.js} +8 -19
  11. package/clients/{listener/child-listener-client.d.ts → listeners/run-listener/pooled-child-listener-client.d.ts} +5 -5
  12. package/clients/{listener/child-listener-client.js → listeners/run-listener/pooled-child-listener-client.js} +5 -5
  13. package/clients/rest/generated/Api.d.ts +49 -2
  14. package/clients/rest/generated/Api.js +30 -0
  15. package/clients/rest/generated/data-contracts.d.ts +88 -82
  16. package/clients/rest/generated/data-contracts.js +8 -1
  17. package/clients/worker/worker.d.ts +5 -1
  18. package/clients/worker/worker.js +173 -2
  19. package/examples/affinity-workers.js +5 -1
  20. package/examples/api.js +1 -1
  21. package/examples/bulk-fanout-worker.js +1 -1
  22. package/examples/byo-logger.js +4 -0
  23. package/examples/concurrency/cancel-in-progress/concurrency-event.js +2 -2
  24. package/examples/concurrency/group-round-robin/concurrency-event.js +1 -1
  25. package/examples/crons/programatic-crons.js +4 -4
  26. package/examples/dag-worker.js +0 -1
  27. package/examples/example-event.js +2 -2
  28. package/examples/logger.js +2 -0
  29. package/examples/on-failure.js +1 -1
  30. package/examples/rate-limit/events.js +3 -3
  31. package/examples/scheduled-runs/programatic-schedules.js +4 -4
  32. package/examples/sticky-worker-with-check.js +2 -2
  33. package/examples/sticky-worker.js +5 -0
  34. package/index.d.ts +1 -3
  35. package/index.js +1 -3
  36. package/package.json +2 -2
  37. package/protoc/dispatcher/dispatcher.d.ts +2 -0
  38. package/protoc/dispatcher/dispatcher.js +1 -1
  39. package/protoc/events/events.js +1 -1
  40. package/protoc/google/protobuf/timestamp.js +1 -1
  41. package/protoc/v1/dispatcher.d.ts +77 -0
  42. package/protoc/v1/dispatcher.js +341 -0
  43. package/protoc/v1/shared/condition.d.ts +59 -0
  44. package/protoc/v1/shared/condition.js +549 -0
  45. package/protoc/v1/workflows.d.ts +263 -0
  46. package/protoc/v1/workflows.js +1823 -0
  47. package/protoc/workflows/workflows.js +1 -1
  48. package/step.d.ts +173 -47
  49. package/step.js +208 -64
  50. package/util/sleep.d.ts +7 -0
  51. package/util/sleep.js +7 -0
  52. package/util/workflow-run-ref.d.ts +8 -2
  53. package/util/workflow-run-ref.js +13 -0
  54. package/v1/client/client.d.ts +125 -7
  55. package/v1/client/client.interface.d.ts +9 -1
  56. package/v1/client/client.js +148 -17
  57. package/v1/client/duration.d.ts +7 -0
  58. package/v1/client/duration.js +2 -0
  59. package/v1/client/features/index.d.ts +5 -0
  60. package/v1/client/features/index.js +21 -0
  61. package/v1/client/features/metrics.d.ts +14 -0
  62. package/v1/client/features/metrics.js +45 -0
  63. package/v1/client/features/ratelimits.d.ts +20 -0
  64. package/v1/client/features/ratelimits.js +40 -0
  65. package/v1/client/features/runs.d.ts +15 -0
  66. package/v1/client/features/runs.js +60 -0
  67. package/v1/client/features/workers.d.ts +14 -0
  68. package/v1/client/features/workers.js +56 -0
  69. package/v1/client/features/workflows.d.ts +17 -0
  70. package/v1/client/features/workflows.js +93 -0
  71. package/v1/client/worker.d.ts +25 -15
  72. package/v1/client/worker.js +76 -47
  73. package/v1/conditions/base.d.ts +18 -0
  74. package/v1/conditions/base.js +18 -0
  75. package/v1/conditions/index.d.ts +31 -0
  76. package/v1/conditions/index.js +91 -0
  77. package/v1/conditions/parent-condition.d.ts +40 -0
  78. package/v1/conditions/parent-condition.js +36 -0
  79. package/v1/conditions/sleep-condition.d.ts +47 -0
  80. package/v1/conditions/sleep-condition.js +38 -0
  81. package/v1/conditions/transformer.d.ts +5 -0
  82. package/v1/conditions/transformer.js +52 -0
  83. package/v1/conditions/user-event-condition.d.ts +50 -0
  84. package/v1/conditions/user-event-condition.js +39 -0
  85. package/v1/declaration.d.ts +309 -0
  86. package/v1/declaration.js +296 -0
  87. package/v1/examples/child_workflows/worker.js +2 -2
  88. package/v1/examples/child_workflows/workflow.d.ts +2 -2
  89. package/v1/examples/child_workflows/workflow.js +5 -3
  90. package/v1/examples/concurrency-rr/load.js +2 -2
  91. package/v1/examples/concurrency-rr/worker.js +2 -2
  92. package/v1/examples/concurrency-rr/workflow.d.ts +1 -1
  93. package/v1/examples/concurrency-rr/workflow.js +2 -3
  94. package/v1/examples/dag/worker.js +2 -2
  95. package/v1/examples/dag/workflow.d.ts +1 -1
  96. package/v1/examples/dag/workflow.js +3 -3
  97. package/v1/examples/dag_match_condition/event.js +28 -0
  98. package/v1/examples/dag_match_condition/run.d.ts +1 -0
  99. package/v1/examples/dag_match_condition/run.js +25 -0
  100. package/v1/examples/dag_match_condition/worker.d.ts +1 -0
  101. package/{examples/playground.js → v1/examples/dag_match_condition/worker.js} +7 -22
  102. package/v1/examples/dag_match_condition/workflow.d.ts +11 -0
  103. package/v1/examples/dag_match_condition/workflow.js +41 -0
  104. package/v1/examples/deep/worker.js +2 -2
  105. package/v1/examples/deep/workflow.d.ts +6 -6
  106. package/v1/examples/deep/workflow.js +7 -7
  107. package/v1/examples/durable-sleep/event.d.ts +1 -0
  108. package/v1/examples/durable-sleep/event.js +28 -0
  109. package/v1/examples/durable-sleep/run.d.ts +1 -0
  110. package/v1/examples/durable-sleep/run.js +30 -0
  111. package/v1/examples/durable-sleep/worker.d.ts +1 -0
  112. package/v1/examples/durable-sleep/worker.js +24 -0
  113. package/v1/examples/durable-sleep/workflow.d.ts +1 -0
  114. package/v1/examples/durable-sleep/workflow.js +37 -0
  115. package/v1/examples/inferred-typing/run.d.ts +1 -0
  116. package/v1/examples/inferred-typing/run.js +41 -0
  117. package/v1/examples/inferred-typing/worker.d.ts +1 -0
  118. package/v1/examples/inferred-typing/worker.js +24 -0
  119. package/v1/examples/inferred-typing/workflow.d.ts +15 -0
  120. package/v1/examples/inferred-typing/workflow.js +44 -0
  121. package/v1/examples/legacy/run.js +2 -2
  122. package/v1/examples/legacy/worker.js +2 -2
  123. package/v1/examples/on_cron/worker.d.ts +1 -0
  124. package/v1/examples/on_cron/worker.js +24 -0
  125. package/v1/examples/on_cron/workflow.d.ts +10 -0
  126. package/v1/examples/on_cron/workflow.js +21 -0
  127. package/v1/examples/on_event/event.js +3 -2
  128. package/v1/examples/on_event/worker.js +2 -2
  129. package/v1/examples/on_event/workflow.d.ts +4 -4
  130. package/v1/examples/on_event/workflow.js +6 -3
  131. package/v1/examples/on_event copy/event.d.ts +1 -0
  132. package/v1/examples/on_event copy/event.js +26 -0
  133. package/v1/examples/on_event copy/worker.d.ts +1 -0
  134. package/v1/examples/on_event copy/worker.js +24 -0
  135. package/v1/examples/on_event copy/workflow.d.ts +16 -0
  136. package/v1/examples/on_event copy/workflow.js +35 -0
  137. package/v1/examples/on_failure/worker.js +2 -2
  138. package/v1/examples/on_failure/workflow.d.ts +1 -1
  139. package/v1/examples/on_failure/workflow.js +16 -5
  140. package/v1/examples/on_success/run.d.ts +1 -0
  141. package/v1/examples/on_success/run.js +31 -0
  142. package/v1/examples/on_success/worker.d.ts +1 -0
  143. package/v1/examples/on_success/worker.js +24 -0
  144. package/v1/examples/on_success/workflow.d.ts +4 -0
  145. package/v1/examples/on_success/workflow.js +59 -0
  146. package/v1/examples/simple/client-run.d.ts +1 -0
  147. package/v1/examples/simple/client-run.js +16 -0
  148. package/v1/examples/simple/cron.js +6 -2
  149. package/v1/examples/simple/delay.js +2 -2
  150. package/v1/examples/simple/enqueue.d.ts +1 -0
  151. package/v1/examples/simple/enqueue.js +43 -0
  152. package/v1/examples/simple/run.js +8 -3
  153. package/v1/examples/simple/schedule.js +11 -5
  154. package/v1/examples/simple/stub-workflow.d.ts +9 -0
  155. package/v1/examples/simple/stub-workflow.js +17 -0
  156. package/v1/examples/simple/worker.js +7 -2
  157. package/v1/examples/simple/workflow.d.ts +4 -3
  158. package/v1/examples/simple/workflow.js +5 -5
  159. package/v1/index.d.ts +5 -0
  160. package/v1/index.js +20 -0
  161. package/v1/task.d.ts +143 -13
  162. package/version.d.ts +1 -1
  163. package/version.js +1 -1
  164. package/v1/workflow.d.ts +0 -158
  165. package/v1/workflow.js +0 -145
  166. /package/{examples/playground.d.ts → v1/examples/dag_match_condition/event.d.ts} +0 -0
  167. /package/v1/examples/{client.d.ts → hatchet-client.d.ts} +0 -0
  168. /package/v1/examples/{client.js → hatchet-client.js} +0 -0
@@ -3,9 +3,10 @@ import { CreateWorkflowVersionOpts, RateLimitDuration, WorkflowServiceClient } f
3
3
  import { ClientConfig } from '../hatchet-client/client-config';
4
4
  import { Logger } from '../../util/logger';
5
5
  import WorkflowRunRef from '../../util/workflow-run-ref';
6
+ import { AdminServiceClient, CreateWorkflowVersionRequest } from '../../protoc/v1/workflows';
6
7
  import { Api } from '../rest';
7
8
  import { WebhookWorkerCreateRequest, WorkflowRunStatus, WorkflowRunStatusList } from '../rest/generated/data-contracts';
8
- import { ListenerClient } from '../listener/listener-client';
9
+ import { RunListenerClient } from '../listeners/run-listener/child-listener-client';
9
10
  type WorkflowMetricsQuery = {
10
11
  workflowId?: string;
11
12
  workflowName?: string;
@@ -23,30 +24,15 @@ export type WorkflowRun<T = object> = {
23
24
  additionalMetadata?: Record<string, string> | undefined;
24
25
  };
25
26
  };
26
- /**
27
- * AdminClient is a client for interacting with the Hatchet Admin API. This allows you to configure, trigger,
28
- * and monitor workflows.
29
- * The admin client can be accessed via:
30
- * ```typescript
31
- * const hatchet = Hatchet.init()
32
- * const admin = hatchet.admin as AdminClient;
33
- *
34
- * // Now you can use the admin client to interact with the Hatchet Admin API
35
- * admin.list_workflows().then((res) => {
36
- * res.rows?.forEach((row) => {
37
- * console.log(row);
38
- * });
39
- * });
40
- * ```
41
- */
42
27
  export declare class AdminClient {
43
28
  config: ClientConfig;
44
29
  client: WorkflowServiceClient;
30
+ v1Client: AdminServiceClient;
45
31
  api: Api;
46
32
  tenantId: string;
47
33
  logger: Logger;
48
- listenerClient: ListenerClient;
49
- constructor(config: ClientConfig, channel: Channel, factory: ClientFactory, api: Api, tenantId: string, listenerClient: ListenerClient);
34
+ listenerClient: RunListenerClient;
35
+ constructor(config: ClientConfig, channel: Channel, factory: ClientFactory, api: Api, tenantId: string, listenerClient: RunListenerClient);
50
36
  /**
51
37
  * @deprecated use putWorkflow instead
52
38
  */
@@ -58,9 +44,18 @@ export declare class AdminClient {
58
44
  */
59
45
  putWorkflow(workflow: CreateWorkflowVersionOpts): Promise<import("../../protoc/workflows").WorkflowVersion>;
60
46
  /**
61
- * @deprecated use putRateLimit instead
47
+ * Creates a new workflow or updates an existing workflow. If the workflow already exists, Hatchet will automatically
48
+ * determine if the workflow definition has changed and create a new version if necessary.
49
+ * @param workflow a workflow definition to create
50
+ */
51
+ putWorkflowV1(workflow: CreateWorkflowVersionRequest): Promise<import("../../protoc/v1/workflows").CreateWorkflowVersionResponse>;
52
+ /**
53
+ * @deprecated use hatchet.ratelimits.upsert instead
62
54
  */
63
55
  put_rate_limit(key: string, limit: number, duration: RateLimitDuration): Promise<void>;
56
+ /**
57
+ * @deprecated use hatchet.ratelimits.upsert instead
58
+ */
64
59
  putRateLimit(key: string, limit: number, duration?: RateLimitDuration): Promise<void>;
65
60
  registerWebhook(data: WebhookWorkerCreateRequest): Promise<import("axios").AxiosResponse<import("../rest/generated/data-contracts").WebhookWorkerCreated, any>>;
66
61
  /**
@@ -17,26 +17,12 @@ const workflows_1 = require("../../protoc/workflows");
17
17
  const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
18
18
  const retrier_1 = require("../../util/retrier");
19
19
  const workflow_run_ref_1 = __importDefault(require("../../util/workflow-run-ref"));
20
- /**
21
- * AdminClient is a client for interacting with the Hatchet Admin API. This allows you to configure, trigger,
22
- * and monitor workflows.
23
- * The admin client can be accessed via:
24
- * ```typescript
25
- * const hatchet = Hatchet.init()
26
- * const admin = hatchet.admin as AdminClient;
27
- *
28
- * // Now you can use the admin client to interact with the Hatchet Admin API
29
- * admin.list_workflows().then((res) => {
30
- * res.rows?.forEach((row) => {
31
- * console.log(row);
32
- * });
33
- * });
34
- * ```
35
- */
20
+ const workflows_2 = require("../../protoc/v1/workflows");
36
21
  class AdminClient {
37
22
  constructor(config, channel, factory, api, tenantId, listenerClient) {
38
23
  this.config = config;
39
24
  this.client = factory.create(workflows_1.WorkflowServiceDefinition, channel);
25
+ this.v1Client = factory.create(workflows_2.AdminServiceDefinition, channel);
40
26
  this.api = api;
41
27
  this.tenantId = tenantId;
42
28
  this.logger = config.logger(`Admin`, config.log_level);
@@ -66,13 +52,31 @@ class AdminClient {
66
52
  });
67
53
  }
68
54
  /**
69
- * @deprecated use putRateLimit instead
55
+ * Creates a new workflow or updates an existing workflow. If the workflow already exists, Hatchet will automatically
56
+ * determine if the workflow definition has changed and create a new version if necessary.
57
+ * @param workflow a workflow definition to create
58
+ */
59
+ putWorkflowV1(workflow) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ try {
62
+ return yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () { return this.v1Client.putWorkflow(workflow); }), this.logger);
63
+ }
64
+ catch (e) {
65
+ throw new hatchet_error_1.default(e.message);
66
+ }
67
+ });
68
+ }
69
+ /**
70
+ * @deprecated use hatchet.ratelimits.upsert instead
70
71
  */
71
72
  put_rate_limit(key, limit, duration) {
72
73
  return __awaiter(this, void 0, void 0, function* () {
73
74
  return this.putRateLimit(key, limit, duration);
74
75
  });
75
76
  }
77
+ /**
78
+ * @deprecated use hatchet.ratelimits.upsert instead
79
+ */
76
80
  putRateLimit(key_1, limit_1) {
77
81
  return __awaiter(this, arguments, void 0, function* (key, limit, duration = workflows_1.RateLimitDuration.SECOND) {
78
82
  try {
@@ -6,12 +6,12 @@ import { Workflow as V0Workflow } from '../../workflow';
6
6
  import { V0Worker, WorkerOpts } from '../worker';
7
7
  import { AxiosRequestConfig } from 'axios';
8
8
  import { Logger } from '../../util/logger';
9
- import { WorkflowDeclaration as V1Workflow } from '../../v1/workflow';
10
9
  import { ClientConfig } from './client-config';
11
- import { ListenerClient } from '../listener/listener-client';
10
+ import { RunListenerClient } from '../listeners/run-listener/child-listener-client';
12
11
  import { Api } from '../rest/generated/Api';
13
12
  import { CronClient } from './features/cron-client';
14
13
  import { ScheduleClient } from './features/schedule-client';
14
+ import { DurableListenerClient } from '../listeners/durable-listener/durable-listener-client';
15
15
  export interface HatchetClientOptions {
16
16
  config_path?: string;
17
17
  credentials?: ChannelCredentials;
@@ -25,8 +25,9 @@ export declare class InternalHatchetClient {
25
25
  dispatcher: DispatcherClient;
26
26
  admin: AdminClient;
27
27
  api: Api;
28
- listener: ListenerClient;
28
+ listener: RunListenerClient;
29
29
  tenantId: string;
30
+ durableListener: DurableListenerClient;
30
31
  logger: Logger;
31
32
  cron: CronClient;
32
33
  schedule: ScheduleClient;
@@ -34,5 +35,5 @@ export declare class InternalHatchetClient {
34
35
  static init(config?: Partial<ClientConfig>, options?: HatchetClientOptions, axiosConfig?: AxiosRequestConfig): InternalHatchetClient;
35
36
  run(workflow: string | V0Workflow): Promise<V0Worker>;
36
37
  worker(workflow: string | V0Workflow, opts?: Omit<WorkerOpts, 'name'> | number): Promise<V0Worker>;
37
- webhooks(workflows: Array<V1Workflow<any, any> | V0Workflow>): import("../worker/handler").WebhookHandler;
38
+ webhooks(workflows: Array<V0Workflow>): import("../worker/handler").WebhookHandler;
38
39
  }
@@ -46,12 +46,12 @@ const admin_client_1 = require("../admin/admin-client");
46
46
  const nice_grpc_1 = require("nice-grpc");
47
47
  const worker_1 = require("../worker");
48
48
  const hatchet_logger_1 = require("./hatchet-logger");
49
- const worker_2 = require("../../v1/client/worker");
50
49
  const client_config_1 = require("./client-config");
51
- const listener_client_1 = require("../listener/listener-client");
50
+ const child_listener_client_1 = require("../listeners/run-listener/child-listener-client");
52
51
  const rest_1 = __importDefault(require("../rest"));
53
52
  const cron_client_1 = require("./features/cron-client");
54
53
  const schedule_client_1 = require("./features/schedule-client");
54
+ const durable_listener_client_1 = require("../listeners/durable-listener/durable-listener-client");
55
55
  const channelFactory = (config, credentials) => (0, nice_grpc_1.createChannel)(config.host_port, credentials, {
56
56
  'grpc.ssl_target_name_override': config.tls_config.server_name,
57
57
  'grpc.keepalive_timeout_ms': 60 * 1000,
@@ -118,8 +118,9 @@ class InternalHatchetClient {
118
118
  this.api = (0, rest_1.default)(this.config.api_url, this.config.token, axiosOpts);
119
119
  this.event = new event_client_1.EventClient(this.config, (0, exports.channelFactory)(this.config, this.credentials), clientFactory);
120
120
  this.dispatcher = new dispatcher_client_1.DispatcherClient(this.config, (0, exports.channelFactory)(this.config, this.credentials), clientFactory);
121
- this.listener = new listener_client_1.ListenerClient(this.config, (0, exports.channelFactory)(this.config, this.credentials), clientFactory, this.api);
121
+ this.listener = new child_listener_client_1.RunListenerClient(this.config, (0, exports.channelFactory)(this.config, this.credentials), clientFactory, this.api);
122
122
  this.admin = new admin_client_1.AdminClient(this.config, (0, exports.channelFactory)(this.config, this.credentials), clientFactory, this.api, this.tenantId, this.listener);
123
+ this.durableListener = new durable_listener_client_1.DurableListenerClient(this.config, (0, exports.channelFactory)(this.config, this.credentials), clientFactory, this.api);
123
124
  this.logger = this.config.logger('HatchetClient', this.config.log_level);
124
125
  this.logger.debug(`Initialized HatchetClient`);
125
126
  // Feature Clients
@@ -160,10 +161,11 @@ class InternalHatchetClient {
160
161
  });
161
162
  }
162
163
  webhooks(workflows) {
164
+ // TODO v1 workflows
163
165
  const worker = new worker_1.V0Worker(this, {
164
166
  name: 'webhook-worker',
165
167
  });
166
- return worker.getHandler(workflows.map(worker_2.toV0Workflow));
168
+ return worker.getHandler(workflows);
167
169
  }
168
170
  }
169
171
  exports.InternalHatchetClient = InternalHatchetClient;
@@ -0,0 +1,25 @@
1
+ import { Channel, ClientFactory } from 'nice-grpc';
2
+ import { ClientConfig } from '../../hatchet-client/client-config';
3
+ import { Logger } from '../../../util/logger';
4
+ import { V1DispatcherClient } from '../../../protoc/v1/dispatcher';
5
+ import { SleepMatchCondition, UserEventMatchCondition } from '../../../protoc/v1/shared/condition';
6
+ import { Api } from '../../rest';
7
+ import { DurableEventGrpcPooledListener } from './pooled-durable-listener-client';
8
+ export declare class DurableListenerClient {
9
+ config: ClientConfig;
10
+ client: V1DispatcherClient;
11
+ logger: Logger;
12
+ api: Api;
13
+ pooledListener: DurableEventGrpcPooledListener | undefined;
14
+ constructor(config: ClientConfig, channel: Channel, factory: ClientFactory, api: Api);
15
+ subscribe(request: {
16
+ taskId: string;
17
+ signalKey: string;
18
+ }): import("./pooled-durable-listener-client").DurableEventStreamable;
19
+ registerDurableEvent(request: {
20
+ taskId: string;
21
+ signalKey: string;
22
+ sleepConditions: Array<SleepMatchCondition>;
23
+ userEventConditions: Array<UserEventMatchCondition>;
24
+ }): Promise<import("../../../protoc/v1/dispatcher").RegisterDurableEventResponse>;
25
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DurableListenerClient = void 0;
4
+ const dispatcher_1 = require("../../../protoc/v1/dispatcher");
5
+ const pooled_durable_listener_client_1 = require("./pooled-durable-listener-client");
6
+ class DurableListenerClient {
7
+ constructor(config, channel, factory, api) {
8
+ this.config = config;
9
+ this.client = factory.create(dispatcher_1.V1DispatcherDefinition, channel);
10
+ this.logger = config.logger(`Listener`, config.log_level);
11
+ this.api = api;
12
+ }
13
+ subscribe(request) {
14
+ if (!this.pooledListener) {
15
+ this.pooledListener = new pooled_durable_listener_client_1.DurableEventGrpcPooledListener(this, () => {
16
+ this.pooledListener = undefined;
17
+ });
18
+ }
19
+ return this.pooledListener.subscribe(request);
20
+ }
21
+ registerDurableEvent(request) {
22
+ if (!this.pooledListener) {
23
+ this.pooledListener = new pooled_durable_listener_client_1.DurableEventGrpcPooledListener(this, () => {
24
+ this.pooledListener = undefined;
25
+ });
26
+ }
27
+ return this.pooledListener.registerDurableEvent(request);
28
+ }
29
+ }
30
+ exports.DurableListenerClient = DurableListenerClient;
@@ -0,0 +1,43 @@
1
+ import { EventEmitter } from 'events';
2
+ import { DurableEvent, RegisterDurableEventResponse } from '../../../protoc/v1/dispatcher';
3
+ import { SleepMatchCondition, UserEventMatchCondition } from '../../../protoc/v1/shared/condition';
4
+ import { DurableListenerClient } from './durable-listener-client';
5
+ export declare class DurableEventStreamable {
6
+ listener: AsyncIterable<DurableEvent>;
7
+ taskId: string;
8
+ signalKey: string;
9
+ responseEmitter: EventEmitter<[never]>;
10
+ constructor(listener: AsyncIterable<DurableEvent>, taskId: string, signalKey: string);
11
+ get(): Promise<DurableEvent>;
12
+ }
13
+ export declare class DurableEventGrpcPooledListener {
14
+ listener: AsyncIterable<DurableEvent> | undefined;
15
+ requestEmitter: EventEmitter<[never]>;
16
+ signal: AbortController;
17
+ client: DurableListenerClient;
18
+ subscribers: Record<string, DurableEventStreamable>;
19
+ taskSignalKeyToSubscriptionIds: Record<string, string[]>;
20
+ onFinish: () => void;
21
+ private subscriptionCounter;
22
+ private currRequester;
23
+ private readonly DEFAULT_INTERRUPT_INTERVAL;
24
+ constructor(client: DurableListenerClient, onFinish: () => void);
25
+ private scheduleInterrupt;
26
+ private init;
27
+ subscribe(request: {
28
+ taskId: string;
29
+ signalKey: string;
30
+ }): DurableEventStreamable;
31
+ result(request: {
32
+ taskId: string;
33
+ signalKey: string;
34
+ }): Promise<DurableEvent>;
35
+ registerDurableEvent(request: {
36
+ taskId: string;
37
+ signalKey: string;
38
+ sleepConditions: Array<SleepMatchCondition>;
39
+ userEventConditions: Array<UserEventMatchCondition>;
40
+ }): Promise<RegisterDurableEventResponse>;
41
+ replayRequests(): void;
42
+ private request;
43
+ }
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
12
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
13
+ var m = o[Symbol.asyncIterator], i;
14
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
15
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
16
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
17
+ };
18
+ var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
19
+ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
20
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
21
+ var g = generator.apply(thisArg, _arguments || []), i, q = [];
22
+ return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
23
+ function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
24
+ function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
25
+ function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
26
+ function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
27
+ function fulfill(value) { resume("next", value); }
28
+ function reject(value) { resume("throw", value); }
29
+ function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
30
+ };
31
+ var __importDefault = (this && this.__importDefault) || function (mod) {
32
+ return (mod && mod.__esModule) ? mod : { "default": mod };
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.DurableEventGrpcPooledListener = exports.DurableEventStreamable = void 0;
36
+ // eslint-disable-next-line max-classes-per-file
37
+ const events_1 = require("events");
38
+ const abort_controller_x_1 = require("abort-controller-x");
39
+ const sleep_1 = __importDefault(require("../../../util/sleep"));
40
+ class DurableEventStreamable {
41
+ constructor(listener, taskId, signalKey) {
42
+ this.responseEmitter = new events_1.EventEmitter();
43
+ this.listener = listener;
44
+ this.taskId = taskId;
45
+ this.signalKey = signalKey;
46
+ }
47
+ get() {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ return new Promise((resolve) => {
50
+ this.responseEmitter.once('response', resolve);
51
+ });
52
+ });
53
+ }
54
+ }
55
+ exports.DurableEventStreamable = DurableEventStreamable;
56
+ class DurableEventGrpcPooledListener {
57
+ constructor(client, onFinish) {
58
+ this.requestEmitter = new events_1.EventEmitter();
59
+ this.signal = new AbortController();
60
+ this.subscribers = {};
61
+ this.taskSignalKeyToSubscriptionIds = {};
62
+ this.onFinish = () => { };
63
+ this.subscriptionCounter = 0;
64
+ this.currRequester = 0;
65
+ this.DEFAULT_INTERRUPT_INTERVAL = 15 * 60 * 1000; // 15 minutes in milliseconds
66
+ this.client = client;
67
+ this.init();
68
+ this.onFinish = onFinish;
69
+ this.scheduleInterrupt();
70
+ }
71
+ scheduleInterrupt() {
72
+ setTimeout(() => {
73
+ if (this.signal) {
74
+ this.signal.abort();
75
+ this.init(0);
76
+ }
77
+ this.scheduleInterrupt();
78
+ }, this.DEFAULT_INTERRUPT_INTERVAL);
79
+ }
80
+ init() {
81
+ return __awaiter(this, arguments, void 0, function* (retries = 0) {
82
+ var _a, e_1, _b, _c;
83
+ let retryCount = retries;
84
+ const MAX_RETRY_INTERVAL = 5000; // 5 seconds in milliseconds
85
+ const BASE_RETRY_INTERVAL = 100; // 0.1 seconds in milliseconds
86
+ const MAX_RETRY_COUNT = 5;
87
+ if (retries > 0) {
88
+ const backoffTime = Math.min(BASE_RETRY_INTERVAL * 2 ** (retries - 1), MAX_RETRY_INTERVAL);
89
+ this.client.logger.info(`Retrying in ... ${backoffTime / 1000} seconds`);
90
+ yield (0, sleep_1.default)(backoffTime);
91
+ }
92
+ if (retries > MAX_RETRY_COUNT) {
93
+ this.client.logger.error('Max retry count exceeded for durable event listener');
94
+ return;
95
+ }
96
+ try {
97
+ this.client.logger.debug('Initializing durable-event-listener');
98
+ this.signal = new AbortController();
99
+ // eslint-disable-next-line no-plusplus
100
+ this.currRequester++;
101
+ this.listener = this.client.client.listenForDurableEvent(this.request(), {
102
+ signal: this.signal.signal,
103
+ });
104
+ if (retries > 0)
105
+ setTimeout(() => this.replayRequests(), 100);
106
+ try {
107
+ for (var _d = true, _e = __asyncValues(this.listener), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
108
+ _c = _f.value;
109
+ _d = false;
110
+ const event = _c;
111
+ retryCount = 0;
112
+ const subscriptionKey = keyHelper(event.taskId, event.signalKey);
113
+ const subscriptionIds = this.taskSignalKeyToSubscriptionIds[subscriptionKey] || [];
114
+ for (const subId of subscriptionIds) {
115
+ const emitter = this.subscribers[subId];
116
+ if (emitter) {
117
+ emitter.responseEmitter.emit('response', event);
118
+ delete this.subscribers[subId];
119
+ // Remove this subscription from the mapping
120
+ this.taskSignalKeyToSubscriptionIds[subscriptionKey] =
121
+ this.taskSignalKeyToSubscriptionIds[subscriptionKey].filter((id) => id !== subId);
122
+ if (this.taskSignalKeyToSubscriptionIds[subscriptionKey].length === 0) {
123
+ delete this.taskSignalKeyToSubscriptionIds[subscriptionKey];
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
130
+ finally {
131
+ try {
132
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
133
+ }
134
+ finally { if (e_1) throw e_1.error; }
135
+ }
136
+ this.client.logger.debug('Durable event listener finished');
137
+ }
138
+ catch (e) {
139
+ if ((0, abort_controller_x_1.isAbortError)(e)) {
140
+ this.client.logger.debug('Durable event listener aborted');
141
+ return;
142
+ }
143
+ this.client.logger.error(`Error in durable-event-listener: ${e.message}`);
144
+ }
145
+ finally {
146
+ const subscriberCount = Object.keys(this.subscribers).length;
147
+ if (subscriberCount > 0) {
148
+ this.client.logger.debug(`Durable event listener loop exited with ${subscriberCount} subscribers`);
149
+ this.client.logger.debug(`Restarting durable event listener retry ${retryCount + 1}`);
150
+ this.init(retryCount + 1);
151
+ }
152
+ }
153
+ });
154
+ }
155
+ subscribe(request) {
156
+ const { taskId, signalKey } = request;
157
+ if (!this.listener)
158
+ throw new Error('listener not initialized');
159
+ // eslint-disable-next-line no-plusplus
160
+ const subscriptionId = (this.subscriptionCounter++).toString();
161
+ const subscriber = new DurableEventStreamable(this.listener, taskId, signalKey);
162
+ this.subscribers[subscriptionId] = subscriber;
163
+ const key = keyHelper(taskId, signalKey);
164
+ if (!this.taskSignalKeyToSubscriptionIds[key]) {
165
+ this.taskSignalKeyToSubscriptionIds[key] = [];
166
+ }
167
+ this.taskSignalKeyToSubscriptionIds[key].push(subscriptionId);
168
+ this.requestEmitter.emit('subscribe', { taskId, signalKey });
169
+ return subscriber;
170
+ }
171
+ result(request) {
172
+ return __awaiter(this, void 0, void 0, function* () {
173
+ const subscriber = this.subscribe(request);
174
+ const event = yield subscriber.get();
175
+ return event;
176
+ });
177
+ }
178
+ registerDurableEvent(request) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const conditions = {
181
+ sleepConditions: request.sleepConditions,
182
+ userEventConditions: request.userEventConditions,
183
+ };
184
+ const registerRequest = {
185
+ taskId: request.taskId,
186
+ signalKey: request.signalKey,
187
+ conditions,
188
+ };
189
+ return this.client.client.registerDurableEvent(registerRequest);
190
+ });
191
+ }
192
+ replayRequests() {
193
+ const subscriptionEntries = Object.entries(this.taskSignalKeyToSubscriptionIds);
194
+ this.client.logger.debug(`Replaying ${subscriptionEntries.length} requests...`);
195
+ for (const [key, _] of subscriptionEntries) {
196
+ const [taskId, signalKey] = key.split('-');
197
+ this.requestEmitter.emit('subscribe', { taskId, signalKey });
198
+ }
199
+ }
200
+ request() {
201
+ return __asyncGenerator(this, arguments, function* request_1() {
202
+ var _a, e_2, _b, _c;
203
+ const { currRequester } = this;
204
+ // Replay existing subscriptions
205
+ const existingSubscriptions = new Set();
206
+ for (const key in this.taskSignalKeyToSubscriptionIds) {
207
+ if (this.taskSignalKeyToSubscriptionIds[key].length > 0) {
208
+ const [taskId, signalKey] = key.split('-');
209
+ existingSubscriptions.add(key);
210
+ yield yield __await({ taskId, signalKey });
211
+ }
212
+ }
213
+ try {
214
+ for (var _d = true, _e = __asyncValues((0, events_1.on)(this.requestEmitter, 'subscribe')), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
215
+ _c = _f.value;
216
+ _d = false;
217
+ const e = _c;
218
+ // Stop if this requester is outdated
219
+ if (currRequester !== this.currRequester)
220
+ break;
221
+ const request = e[0];
222
+ const key = keyHelper(request.taskId, request.signalKey);
223
+ // Only send unique subscriptions
224
+ if (!existingSubscriptions.has(key)) {
225
+ existingSubscriptions.add(key);
226
+ yield yield __await(request);
227
+ }
228
+ }
229
+ }
230
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
231
+ finally {
232
+ try {
233
+ if (!_d && !_a && (_b = _e.return)) yield __await(_b.call(_e));
234
+ }
235
+ finally { if (e_2) throw e_2.error; }
236
+ }
237
+ });
238
+ }
239
+ }
240
+ exports.DurableEventGrpcPooledListener = DurableEventGrpcPooledListener;
241
+ const keyHelper = (taskId, signalKey) => `${taskId}-${signalKey}`;
@@ -1,10 +1,10 @@
1
1
  import { Channel, ClientFactory } from 'nice-grpc';
2
2
  import { EventEmitter } from 'events';
3
- import { DispatcherClient as PbDispatcherClient, DispatcherClient, WorkflowEvent } from '../../protoc/dispatcher';
4
- import { ClientConfig } from '../hatchet-client/client-config';
5
- import { Logger } from '../../util/logger';
6
- import { Api } from '../rest';
7
- import { GrpcPooledListener } from './child-listener-client';
3
+ import { DispatcherClient as PbDispatcherClient, DispatcherClient, WorkflowEvent } from '../../../protoc/dispatcher';
4
+ import { ClientConfig } from '../../hatchet-client/client-config';
5
+ import { Logger } from '../../../util/logger';
6
+ import { Api } from '../../rest';
7
+ import { RunGrpcPooledListener } from './pooled-child-listener-client';
8
8
  export declare enum RunEventType {
9
9
  STEP_RUN_EVENT_TYPE_STARTED = "STEP_RUN_EVENT_TYPE_STARTED",
10
10
  STEP_RUN_EVENT_TYPE_COMPLETED = "STEP_RUN_EVENT_TYPE_COMPLETED",
@@ -39,14 +39,14 @@ export declare class RunEventListener {
39
39
  retrySubscribe(listenerFactory: () => AsyncIterable<WorkflowEvent>): Promise<AsyncIterable<WorkflowEvent>>;
40
40
  stream(): AsyncGenerator<StepRunEvent, void, unknown>;
41
41
  }
42
- export declare class ListenerClient {
42
+ export declare class RunListenerClient {
43
43
  config: ClientConfig;
44
44
  client: PbDispatcherClient;
45
45
  logger: Logger;
46
46
  api: Api;
47
- pooledListener: GrpcPooledListener | undefined;
47
+ pooledListener: RunGrpcPooledListener | undefined;
48
48
  constructor(config: ClientConfig, channel: Channel, factory: ClientFactory, api: Api);
49
- get(workflowRunId: string): import("./child-listener-client").Streamable;
49
+ get(workflowRunId: string): import("./pooled-child-listener-client").Streamable;
50
50
  stream(workflowRunId: string): Promise<AsyncGenerator<StepRunEvent, void, unknown>>;
51
51
  streamByRunId(workflowRunId: string): Promise<AsyncGenerator<StepRunEvent, void, unknown>>;
52
52
  streamByAdditionalMeta(key: string, value: string): Promise<AsyncGenerator<StepRunEvent, void, unknown>>;
@@ -32,18 +32,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
32
32
  return (mod && mod.__esModule) ? mod : { "default": mod };
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.ListenerClient = exports.RunEventListener = exports.RunEventType = void 0;
35
+ exports.RunListenerClient = exports.RunEventListener = exports.RunEventType = void 0;
36
36
  // eslint-disable-next-line max-classes-per-file
37
37
  const nice_grpc_1 = require("nice-grpc");
38
38
  const events_1 = require("events");
39
- const dispatcher_1 = require("../../protoc/dispatcher");
40
- const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
41
- const sleep_1 = __importDefault(require("../../util/sleep"));
42
- const data_contracts_1 = require("../rest/generated/data-contracts");
43
- const child_listener_client_1 = require("./child-listener-client");
39
+ const dispatcher_1 = require("../../../protoc/dispatcher");
40
+ const hatchet_error_1 = __importDefault(require("../../../util/errors/hatchet-error"));
41
+ const sleep_1 = __importDefault(require("../../../util/sleep"));
42
+ const pooled_child_listener_client_1 = require("./pooled-child-listener-client");
44
43
  const DEFAULT_EVENT_LISTENER_RETRY_INTERVAL = 5; // seconds
45
44
  const DEFAULT_EVENT_LISTENER_RETRY_COUNT = 5;
46
- const DEFAULT_EVENT_LISTENER_POLL_INTERVAL = 5000; // milliseconds
47
45
  // eslint-disable-next-line no-shadow
48
46
  var RunEventType;
49
47
  (function (RunEventType) {
@@ -85,15 +83,6 @@ const resourceTypeMap = {
85
83
  [dispatcher_1.ResourceType.RESOURCE_TYPE_UNKNOWN]: undefined,
86
84
  [dispatcher_1.ResourceType.UNRECOGNIZED]: undefined,
87
85
  };
88
- const workflowStatusMap = {
89
- [data_contracts_1.WorkflowRunStatus.SUCCEEDED]: RunEventType.WORKFLOW_RUN_EVENT_TYPE_COMPLETED,
90
- [data_contracts_1.WorkflowRunStatus.FAILED]: RunEventType.WORKFLOW_RUN_EVENT_TYPE_FAILED,
91
- [data_contracts_1.WorkflowRunStatus.CANCELLED]: RunEventType.WORKFLOW_RUN_EVENT_TYPE_CANCELLED,
92
- [data_contracts_1.WorkflowRunStatus.PENDING]: undefined,
93
- [data_contracts_1.WorkflowRunStatus.RUNNING]: undefined,
94
- [data_contracts_1.WorkflowRunStatus.QUEUED]: undefined,
95
- [data_contracts_1.WorkflowRunStatus.BACKOFF]: undefined,
96
- };
97
86
  class RunEventListener {
98
87
  constructor(client) {
99
88
  this.q = [];
@@ -213,7 +202,7 @@ class RunEventListener {
213
202
  }
214
203
  }
215
204
  exports.RunEventListener = RunEventListener;
216
- class ListenerClient {
205
+ class RunListenerClient {
217
206
  constructor(config, channel, factory, api) {
218
207
  this.config = config;
219
208
  this.client = factory.create(dispatcher_1.DispatcherDefinition, channel);
@@ -222,7 +211,7 @@ class ListenerClient {
222
211
  }
223
212
  get(workflowRunId) {
224
213
  if (!this.pooledListener) {
225
- this.pooledListener = new child_listener_client_1.GrpcPooledListener(this, () => {
214
+ this.pooledListener = new pooled_child_listener_client_1.RunGrpcPooledListener(this, () => {
226
215
  this.pooledListener = undefined;
227
216
  });
228
217
  }
@@ -248,4 +237,4 @@ class ListenerClient {
248
237
  });
249
238
  }
250
239
  }
251
- exports.ListenerClient = ListenerClient;
240
+ exports.RunListenerClient = RunListenerClient;