@hatchet-dev/typescript-sdk 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,10 @@ import { DispatcherClient as PbDispatcherClient, AssignedAction } from '../../pr
2
2
  import { ClientConfig } from '../hatchet-client/client-config';
3
3
  import { Logger } from '../../util/logger';
4
4
  import { DispatcherClient } from './dispatcher-client';
5
+ declare enum ListenStrategy {
6
+ LISTEN_STRATEGY_V1 = 1,
7
+ LISTEN_STRATEGY_V2 = 2
8
+ }
5
9
  export interface Action {
6
10
  tenantId: string;
7
11
  jobId: string;
@@ -26,9 +30,16 @@ export declare class ActionListener {
26
30
  retryInterval: number;
27
31
  retryCount: number;
28
32
  done: boolean;
33
+ listenStrategy: ListenStrategy;
34
+ heartbeatInterval: any;
29
35
  constructor(client: DispatcherClient, workerId: string, retryInterval?: number, retryCount?: number);
30
36
  actions: () => AsyncGenerator<Action, void, unknown>;
37
+ setListenStrategy(strategy: ListenStrategy): Promise<void>;
38
+ getListenStrategy(): Promise<ListenStrategy>;
31
39
  incrementRetries(): Promise<void>;
40
+ heartbeat(): Promise<void>;
41
+ closeHeartbeat(): void;
32
42
  getListenClient(): Promise<AsyncIterable<AssignedAction>>;
33
43
  unregister(): Promise<import("../../protoc/dispatcher").WorkerUnsubscribeResponse>;
34
44
  }
45
+ export {};
@@ -39,6 +39,12 @@ const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error
39
39
  const logger_1 = require("../../util/logger");
40
40
  const DEFAULT_ACTION_LISTENER_RETRY_INTERVAL = 5000; // milliseconds
41
41
  const DEFAULT_ACTION_LISTENER_RETRY_COUNT = 5;
42
+ // eslint-disable-next-line no-shadow
43
+ var ListenStrategy;
44
+ (function (ListenStrategy) {
45
+ ListenStrategy[ListenStrategy["LISTEN_STRATEGY_V1"] = 1] = "LISTEN_STRATEGY_V1";
46
+ ListenStrategy[ListenStrategy["LISTEN_STRATEGY_V2"] = 2] = "LISTEN_STRATEGY_V2";
47
+ })(ListenStrategy || (ListenStrategy = {}));
42
48
  class ActionListener {
43
49
  constructor(client, workerId, retryInterval = DEFAULT_ACTION_LISTENER_RETRY_INTERVAL, retryCount = DEFAULT_ACTION_LISTENER_RETRY_COUNT) {
44
50
  this.lastConnectionAttempt = 0;
@@ -46,6 +52,7 @@ class ActionListener {
46
52
  this.retryInterval = DEFAULT_ACTION_LISTENER_RETRY_INTERVAL;
47
53
  this.retryCount = DEFAULT_ACTION_LISTENER_RETRY_COUNT;
48
54
  this.done = false;
55
+ this.listenStrategy = ListenStrategy.LISTEN_STRATEGY_V2;
49
56
  this.actions = () => (function gen(client) {
50
57
  return __asyncGenerator(this, arguments, function* gen_1() {
51
58
  var _a, e_1, _b, _c;
@@ -79,6 +86,10 @@ class ActionListener {
79
86
  if (e.code === nice_grpc_1.Status.CANCELLED) {
80
87
  break;
81
88
  }
89
+ if ((yield __await(client.getListenStrategy())) === ListenStrategy.LISTEN_STRATEGY_V2 &&
90
+ e.code === nice_grpc_1.Status.UNIMPLEMENTED) {
91
+ client.setListenStrategy(ListenStrategy.LISTEN_STRATEGY_V1);
92
+ }
82
93
  client.incrementRetries();
83
94
  }
84
95
  }
@@ -91,11 +102,62 @@ class ActionListener {
91
102
  this.retryInterval = retryInterval;
92
103
  this.retryCount = retryCount;
93
104
  }
105
+ setListenStrategy(strategy) {
106
+ return __awaiter(this, void 0, void 0, function* () {
107
+ this.listenStrategy = strategy;
108
+ });
109
+ }
110
+ getListenStrategy() {
111
+ return __awaiter(this, void 0, void 0, function* () {
112
+ return this.listenStrategy;
113
+ });
114
+ }
94
115
  incrementRetries() {
95
116
  return __awaiter(this, void 0, void 0, function* () {
96
117
  this.retries += 1;
97
118
  });
98
119
  }
120
+ heartbeat() {
121
+ return __awaiter(this, void 0, void 0, function* () {
122
+ if (this.heartbeatInterval) {
123
+ return;
124
+ }
125
+ // start with a heartbeat
126
+ try {
127
+ yield this.client.heartbeat({
128
+ workerId: this.workerId,
129
+ heartbeatAt: new Date(),
130
+ });
131
+ }
132
+ catch (e) {
133
+ this.logger.error(`Failed to send heartbeat: ${e.message}`);
134
+ if (e.code === nice_grpc_1.Status.UNIMPLEMENTED) {
135
+ return;
136
+ }
137
+ }
138
+ this.heartbeatInterval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
139
+ try {
140
+ yield this.client.heartbeat({
141
+ workerId: this.workerId,
142
+ heartbeatAt: new Date(),
143
+ });
144
+ }
145
+ catch (e) {
146
+ if (e.code === nice_grpc_1.Status.UNIMPLEMENTED) {
147
+ // break out of interval
148
+ this.closeHeartbeat();
149
+ return;
150
+ }
151
+ this.logger.error(`Failed to send heartbeat: ${e.message}`);
152
+ }
153
+ }), 4000);
154
+ });
155
+ }
156
+ closeHeartbeat() {
157
+ if (this.heartbeatInterval) {
158
+ clearInterval(this.heartbeatInterval);
159
+ }
160
+ }
99
161
  getListenClient() {
100
162
  return __awaiter(this, void 0, void 0, function* () {
101
163
  const currentTime = Math.floor(Date.now());
@@ -112,9 +174,16 @@ class ActionListener {
112
174
  yield (0, sleep_1.default)(DEFAULT_ACTION_LISTENER_RETRY_INTERVAL);
113
175
  }
114
176
  try {
115
- return this.client.listen({
177
+ if (this.listenStrategy === ListenStrategy.LISTEN_STRATEGY_V1) {
178
+ return this.client.listen({
179
+ workerId: this.workerId,
180
+ });
181
+ }
182
+ const res = this.client.listenV2({
116
183
  workerId: this.workerId,
117
184
  });
185
+ this.heartbeat();
186
+ return res;
118
187
  }
119
188
  catch (e) {
120
189
  this.retries += 1;
@@ -126,6 +195,7 @@ class ActionListener {
126
195
  unregister() {
127
196
  return __awaiter(this, void 0, void 0, function* () {
128
197
  this.done = true;
198
+ this.closeHeartbeat();
129
199
  try {
130
200
  return this.client.unsubscribe({
131
201
  workerId: this.workerId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatchet-dev/typescript-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Background task orchestration & visibility for developers",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -178,6 +178,14 @@ export interface OverridesData {
178
178
  }
179
179
  export interface OverridesDataResponse {
180
180
  }
181
+ export interface HeartbeatRequest {
182
+ /** the id of the worker */
183
+ workerId: string;
184
+ /** heartbeatAt is the time the worker sent the heartbeat */
185
+ heartbeatAt: Date | undefined;
186
+ }
187
+ export interface HeartbeatResponse {
188
+ }
181
189
  export declare const WorkerRegisterRequest: {
182
190
  encode(message: WorkerRegisterRequest, writer?: _m0.Writer): _m0.Writer;
183
191
  decode(input: _m0.Reader | Uint8Array, length?: number): WorkerRegisterRequest;
@@ -282,6 +290,22 @@ export declare const OverridesDataResponse: {
282
290
  create(base?: DeepPartial<OverridesDataResponse>): OverridesDataResponse;
283
291
  fromPartial(_: DeepPartial<OverridesDataResponse>): OverridesDataResponse;
284
292
  };
293
+ export declare const HeartbeatRequest: {
294
+ encode(message: HeartbeatRequest, writer?: _m0.Writer): _m0.Writer;
295
+ decode(input: _m0.Reader | Uint8Array, length?: number): HeartbeatRequest;
296
+ fromJSON(object: any): HeartbeatRequest;
297
+ toJSON(message: HeartbeatRequest): unknown;
298
+ create(base?: DeepPartial<HeartbeatRequest>): HeartbeatRequest;
299
+ fromPartial(object: DeepPartial<HeartbeatRequest>): HeartbeatRequest;
300
+ };
301
+ export declare const HeartbeatResponse: {
302
+ encode(_: HeartbeatResponse, writer?: _m0.Writer): _m0.Writer;
303
+ decode(input: _m0.Reader | Uint8Array, length?: number): HeartbeatResponse;
304
+ fromJSON(_: any): HeartbeatResponse;
305
+ toJSON(_: HeartbeatResponse): unknown;
306
+ create(base?: DeepPartial<HeartbeatResponse>): HeartbeatResponse;
307
+ fromPartial(_: DeepPartial<HeartbeatResponse>): HeartbeatResponse;
308
+ };
285
309
  export type DispatcherDefinition = typeof DispatcherDefinition;
286
310
  export declare const DispatcherDefinition: {
287
311
  readonly name: "Dispatcher";
@@ -331,6 +355,55 @@ export declare const DispatcherDefinition: {
331
355
  readonly responseStream: true;
332
356
  readonly options: {};
333
357
  };
358
+ /**
359
+ * ListenV2 is like listen, but implementation does not include heartbeats. This should only used by SDKs
360
+ * against engine version v0.18.1+
361
+ */
362
+ readonly listenV2: {
363
+ readonly name: "ListenV2";
364
+ readonly requestType: {
365
+ encode(message: WorkerListenRequest, writer?: _m0.Writer): _m0.Writer;
366
+ decode(input: _m0.Reader | Uint8Array, length?: number): WorkerListenRequest;
367
+ fromJSON(object: any): WorkerListenRequest;
368
+ toJSON(message: WorkerListenRequest): unknown;
369
+ create(base?: DeepPartial<WorkerListenRequest>): WorkerListenRequest;
370
+ fromPartial(object: DeepPartial<WorkerListenRequest>): WorkerListenRequest;
371
+ };
372
+ readonly requestStream: false;
373
+ readonly responseType: {
374
+ encode(message: AssignedAction, writer?: _m0.Writer): _m0.Writer;
375
+ decode(input: _m0.Reader | Uint8Array, length?: number): AssignedAction;
376
+ fromJSON(object: any): AssignedAction;
377
+ toJSON(message: AssignedAction): unknown;
378
+ create(base?: DeepPartial<AssignedAction>): AssignedAction;
379
+ fromPartial(object: DeepPartial<AssignedAction>): AssignedAction;
380
+ };
381
+ readonly responseStream: true;
382
+ readonly options: {};
383
+ };
384
+ /** Heartbeat is a method for workers to send heartbeats to the dispatcher */
385
+ readonly heartbeat: {
386
+ readonly name: "Heartbeat";
387
+ readonly requestType: {
388
+ encode(message: HeartbeatRequest, writer?: _m0.Writer): _m0.Writer;
389
+ decode(input: _m0.Reader | Uint8Array, length?: number): HeartbeatRequest;
390
+ fromJSON(object: any): HeartbeatRequest;
391
+ toJSON(message: HeartbeatRequest): unknown;
392
+ create(base?: DeepPartial<HeartbeatRequest>): HeartbeatRequest;
393
+ fromPartial(object: DeepPartial<HeartbeatRequest>): HeartbeatRequest;
394
+ };
395
+ readonly requestStream: false;
396
+ readonly responseType: {
397
+ encode(_: HeartbeatResponse, writer?: _m0.Writer): _m0.Writer;
398
+ decode(input: _m0.Reader | Uint8Array, length?: number): HeartbeatResponse;
399
+ fromJSON(_: any): HeartbeatResponse;
400
+ toJSON(_: HeartbeatResponse): unknown;
401
+ create(base?: DeepPartial<HeartbeatResponse>): HeartbeatResponse;
402
+ fromPartial(_: DeepPartial<HeartbeatResponse>): HeartbeatResponse;
403
+ };
404
+ readonly responseStream: false;
405
+ readonly options: {};
406
+ };
334
407
  readonly subscribeToWorkflowEvents: {
335
408
  readonly name: "SubscribeToWorkflowEvents";
336
409
  readonly requestType: {
@@ -446,6 +519,13 @@ export declare const DispatcherDefinition: {
446
519
  export interface DispatcherServiceImplementation<CallContextExt = {}> {
447
520
  register(request: WorkerRegisterRequest, context: CallContext & CallContextExt): Promise<DeepPartial<WorkerRegisterResponse>>;
448
521
  listen(request: WorkerListenRequest, context: CallContext & CallContextExt): ServerStreamingMethodResult<DeepPartial<AssignedAction>>;
522
+ /**
523
+ * ListenV2 is like listen, but implementation does not include heartbeats. This should only used by SDKs
524
+ * against engine version v0.18.1+
525
+ */
526
+ listenV2(request: WorkerListenRequest, context: CallContext & CallContextExt): ServerStreamingMethodResult<DeepPartial<AssignedAction>>;
527
+ /** Heartbeat is a method for workers to send heartbeats to the dispatcher */
528
+ heartbeat(request: HeartbeatRequest, context: CallContext & CallContextExt): Promise<DeepPartial<HeartbeatResponse>>;
449
529
  subscribeToWorkflowEvents(request: SubscribeToWorkflowEventsRequest, context: CallContext & CallContextExt): ServerStreamingMethodResult<DeepPartial<WorkflowEvent>>;
450
530
  sendStepActionEvent(request: StepActionEvent, context: CallContext & CallContextExt): Promise<DeepPartial<ActionEventResponse>>;
451
531
  sendGroupKeyActionEvent(request: GroupKeyActionEvent, context: CallContext & CallContextExt): Promise<DeepPartial<ActionEventResponse>>;
@@ -455,6 +535,13 @@ export interface DispatcherServiceImplementation<CallContextExt = {}> {
455
535
  export interface DispatcherClient<CallOptionsExt = {}> {
456
536
  register(request: DeepPartial<WorkerRegisterRequest>, options?: CallOptions & CallOptionsExt): Promise<WorkerRegisterResponse>;
457
537
  listen(request: DeepPartial<WorkerListenRequest>, options?: CallOptions & CallOptionsExt): AsyncIterable<AssignedAction>;
538
+ /**
539
+ * ListenV2 is like listen, but implementation does not include heartbeats. This should only used by SDKs
540
+ * against engine version v0.18.1+
541
+ */
542
+ listenV2(request: DeepPartial<WorkerListenRequest>, options?: CallOptions & CallOptionsExt): AsyncIterable<AssignedAction>;
543
+ /** Heartbeat is a method for workers to send heartbeats to the dispatcher */
544
+ heartbeat(request: DeepPartial<HeartbeatRequest>, options?: CallOptions & CallOptionsExt): Promise<HeartbeatResponse>;
458
545
  subscribeToWorkflowEvents(request: DeepPartial<SubscribeToWorkflowEventsRequest>, options?: CallOptions & CallOptionsExt): AsyncIterable<WorkflowEvent>;
459
546
  sendStepActionEvent(request: DeepPartial<StepActionEvent>, options?: CallOptions & CallOptionsExt): Promise<ActionEventResponse>;
460
547
  sendGroupKeyActionEvent(request: DeepPartial<GroupKeyActionEvent>, options?: CallOptions & CallOptionsExt): Promise<ActionEventResponse>;
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.DispatcherDefinition = exports.OverridesDataResponse = exports.OverridesData = exports.WorkflowEvent = exports.SubscribeToWorkflowEventsRequest = exports.ActionEventResponse = exports.StepActionEvent = exports.GroupKeyActionEvent = exports.WorkerUnsubscribeResponse = exports.WorkerUnsubscribeRequest = exports.WorkerListenRequest = exports.AssignedAction = exports.WorkerRegisterResponse = exports.WorkerRegisterRequest = exports.resourceEventTypeToJSON = exports.resourceEventTypeFromJSON = exports.ResourceEventType = exports.resourceTypeToJSON = exports.resourceTypeFromJSON = exports.ResourceType = exports.stepActionEventTypeToJSON = exports.stepActionEventTypeFromJSON = exports.StepActionEventType = exports.groupKeyActionEventTypeToJSON = exports.groupKeyActionEventTypeFromJSON = exports.GroupKeyActionEventType = exports.actionTypeToJSON = exports.actionTypeFromJSON = exports.ActionType = exports.protobufPackage = void 0;
26
+ exports.DispatcherDefinition = exports.HeartbeatResponse = exports.HeartbeatRequest = exports.OverridesDataResponse = exports.OverridesData = exports.WorkflowEvent = exports.SubscribeToWorkflowEventsRequest = exports.ActionEventResponse = exports.StepActionEvent = exports.GroupKeyActionEvent = exports.WorkerUnsubscribeResponse = exports.WorkerUnsubscribeRequest = exports.WorkerListenRequest = exports.AssignedAction = exports.WorkerRegisterResponse = exports.WorkerRegisterRequest = exports.resourceEventTypeToJSON = exports.resourceEventTypeFromJSON = exports.ResourceEventType = exports.resourceTypeToJSON = exports.resourceTypeFromJSON = exports.ResourceType = exports.stepActionEventTypeToJSON = exports.stepActionEventTypeFromJSON = exports.StepActionEventType = exports.groupKeyActionEventTypeToJSON = exports.groupKeyActionEventTypeFromJSON = exports.GroupKeyActionEventType = exports.actionTypeToJSON = exports.actionTypeFromJSON = exports.ActionType = exports.protobufPackage = void 0;
27
27
  const _m0 = __importStar(require("protobufjs/minimal"));
28
28
  const timestamp_1 = require("../google/protobuf/timestamp");
29
29
  exports.protobufPackage = '';
@@ -1579,6 +1579,110 @@ exports.OverridesDataResponse = {
1579
1579
  return message;
1580
1580
  },
1581
1581
  };
1582
+ function createBaseHeartbeatRequest() {
1583
+ return { workerId: '', heartbeatAt: undefined };
1584
+ }
1585
+ exports.HeartbeatRequest = {
1586
+ encode(message, writer = _m0.Writer.create()) {
1587
+ if (message.workerId !== '') {
1588
+ writer.uint32(10).string(message.workerId);
1589
+ }
1590
+ if (message.heartbeatAt !== undefined) {
1591
+ timestamp_1.Timestamp.encode(toTimestamp(message.heartbeatAt), writer.uint32(18).fork()).ldelim();
1592
+ }
1593
+ return writer;
1594
+ },
1595
+ decode(input, length) {
1596
+ const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
1597
+ let end = length === undefined ? reader.len : reader.pos + length;
1598
+ const message = createBaseHeartbeatRequest();
1599
+ while (reader.pos < end) {
1600
+ const tag = reader.uint32();
1601
+ switch (tag >>> 3) {
1602
+ case 1:
1603
+ if (tag !== 10) {
1604
+ break;
1605
+ }
1606
+ message.workerId = reader.string();
1607
+ continue;
1608
+ case 2:
1609
+ if (tag !== 18) {
1610
+ break;
1611
+ }
1612
+ message.heartbeatAt = fromTimestamp(timestamp_1.Timestamp.decode(reader, reader.uint32()));
1613
+ continue;
1614
+ }
1615
+ if ((tag & 7) === 4 || tag === 0) {
1616
+ break;
1617
+ }
1618
+ reader.skipType(tag & 7);
1619
+ }
1620
+ return message;
1621
+ },
1622
+ fromJSON(object) {
1623
+ return {
1624
+ workerId: isSet(object.workerId) ? globalThis.String(object.workerId) : '',
1625
+ heartbeatAt: isSet(object.heartbeatAt) ? fromJsonTimestamp(object.heartbeatAt) : undefined,
1626
+ };
1627
+ },
1628
+ toJSON(message) {
1629
+ const obj = {};
1630
+ if (message.workerId !== '') {
1631
+ obj.workerId = message.workerId;
1632
+ }
1633
+ if (message.heartbeatAt !== undefined) {
1634
+ obj.heartbeatAt = message.heartbeatAt.toISOString();
1635
+ }
1636
+ return obj;
1637
+ },
1638
+ create(base) {
1639
+ return exports.HeartbeatRequest.fromPartial(base !== null && base !== void 0 ? base : {});
1640
+ },
1641
+ fromPartial(object) {
1642
+ var _a, _b;
1643
+ const message = createBaseHeartbeatRequest();
1644
+ message.workerId = (_a = object.workerId) !== null && _a !== void 0 ? _a : '';
1645
+ message.heartbeatAt = (_b = object.heartbeatAt) !== null && _b !== void 0 ? _b : undefined;
1646
+ return message;
1647
+ },
1648
+ };
1649
+ function createBaseHeartbeatResponse() {
1650
+ return {};
1651
+ }
1652
+ exports.HeartbeatResponse = {
1653
+ encode(_, writer = _m0.Writer.create()) {
1654
+ return writer;
1655
+ },
1656
+ decode(input, length) {
1657
+ const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
1658
+ let end = length === undefined ? reader.len : reader.pos + length;
1659
+ const message = createBaseHeartbeatResponse();
1660
+ while (reader.pos < end) {
1661
+ const tag = reader.uint32();
1662
+ switch (tag >>> 3) {
1663
+ }
1664
+ if ((tag & 7) === 4 || tag === 0) {
1665
+ break;
1666
+ }
1667
+ reader.skipType(tag & 7);
1668
+ }
1669
+ return message;
1670
+ },
1671
+ fromJSON(_) {
1672
+ return {};
1673
+ },
1674
+ toJSON(_) {
1675
+ const obj = {};
1676
+ return obj;
1677
+ },
1678
+ create(base) {
1679
+ return exports.HeartbeatResponse.fromPartial(base !== null && base !== void 0 ? base : {});
1680
+ },
1681
+ fromPartial(_) {
1682
+ const message = createBaseHeartbeatResponse();
1683
+ return message;
1684
+ },
1685
+ };
1582
1686
  exports.DispatcherDefinition = {
1583
1687
  name: 'Dispatcher',
1584
1688
  fullName: 'Dispatcher',
@@ -1599,6 +1703,27 @@ exports.DispatcherDefinition = {
1599
1703
  responseStream: true,
1600
1704
  options: {},
1601
1705
  },
1706
+ /**
1707
+ * ListenV2 is like listen, but implementation does not include heartbeats. This should only used by SDKs
1708
+ * against engine version v0.18.1+
1709
+ */
1710
+ listenV2: {
1711
+ name: 'ListenV2',
1712
+ requestType: exports.WorkerListenRequest,
1713
+ requestStream: false,
1714
+ responseType: exports.AssignedAction,
1715
+ responseStream: true,
1716
+ options: {},
1717
+ },
1718
+ /** Heartbeat is a method for workers to send heartbeats to the dispatcher */
1719
+ heartbeat: {
1720
+ name: 'Heartbeat',
1721
+ requestType: exports.HeartbeatRequest,
1722
+ requestStream: false,
1723
+ responseType: exports.HeartbeatResponse,
1724
+ responseStream: false,
1725
+ options: {},
1726
+ },
1602
1727
  subscribeToWorkflowEvents: {
1603
1728
  name: 'SubscribeToWorkflowEvents',
1604
1729
  requestType: exports.SubscribeToWorkflowEventsRequest,