@hatchet-dev/typescript-sdk 0.15.1-alpha6 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { Channel, ClientFactory } from 'nice-grpc';
2
- import { DispatcherClient as PbDispatcherClient, StepActionEvent, GroupKeyActionEvent, OverridesData, DeepPartial } from '../../protoc/dispatcher';
2
+ import { DispatcherClient as PbDispatcherClient, StepActionEvent, GroupKeyActionEvent, OverridesData, DeepPartial, RuntimeInfo } from '../../protoc/dispatcher';
3
3
  import { ClientConfig } from '../hatchet-client/client-config';
4
4
  import { Logger } from '../../util/logger';
5
5
  import { ActionListener } from './action-listener';
@@ -16,6 +16,7 @@ export declare class DispatcherClient {
16
16
  client: PbDispatcherClient;
17
17
  logger: Logger;
18
18
  constructor(config: ClientConfig, channel: Channel, factory: ClientFactory);
19
+ getRuntimeInfo(): RuntimeInfo;
19
20
  getActionListener(options: GetActionListenerOptions): Promise<ActionListener>;
20
21
  sendStepActionEvent(in_: StepActionEvent): Promise<import("../../protoc/dispatcher").ActionEventResponse>;
21
22
  sendGroupKeyActionEvent(in_: GroupKeyActionEvent): Promise<import("../../protoc/dispatcher").ActionEventResponse>;
@@ -17,6 +17,7 @@ const dispatcher_1 = require("../../protoc/dispatcher");
17
17
  const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
18
18
  const logger_1 = require("../../util/logger");
19
19
  const retrier_1 = require("../../util/retrier");
20
+ const version_1 = require("../../version");
20
21
  const action_listener_1 = require("./action-listener");
21
22
  class DispatcherClient {
22
23
  constructor(config, channel, factory) {
@@ -24,10 +25,18 @@ class DispatcherClient {
24
25
  this.client = factory.create(dispatcher_1.DispatcherDefinition, channel);
25
26
  this.logger = new logger_1.Logger(`Dispatcher`, config.log_level);
26
27
  }
28
+ getRuntimeInfo() {
29
+ return {
30
+ sdkVersion: version_1.HATCHET_VERSION,
31
+ language: dispatcher_1.SDKS.TYPESCRIPT,
32
+ languageVersion: process.version,
33
+ os: process.platform,
34
+ };
35
+ }
27
36
  getActionListener(options) {
28
37
  return __awaiter(this, void 0, void 0, function* () {
29
38
  // Register the worker
30
- const registration = yield this.client.register(Object.assign(Object.assign({}, options), { labels: options.labels ? mapLabels(options.labels) : undefined }));
39
+ const registration = yield this.client.register(Object.assign(Object.assign({}, options), { labels: options.labels ? mapLabels(options.labels) : undefined, runtimeInfo: this.getRuntimeInfo() }));
31
40
  return new action_listener_1.ActionListener(this, registration.workerId);
32
41
  });
33
42
  }
@@ -84,20 +84,22 @@ class EventClient {
84
84
  }
85
85
  putLog(stepRunId, log, level) {
86
86
  const createdAt = new Date();
87
- // retrier(
88
- // async () =>
89
- // this.client.putLog({
90
- // stepRunId,
91
- // createdAt,
92
- // message: log,
93
- // level: level || LogLevel.INFO,
94
- // }),
95
- // this.logger
96
- // ).catch((e: any) => {
97
- // // log a warning, but this is not a fatal error
98
- // console.error(e);
99
- // // this.logger.warn(`Could not put log: ${e.message.substring(0, 100)}`);
100
- // });
87
+ if (log.length > 1000) {
88
+ this.logger.warn(`log is too long, skipping: ${log.length} characters`);
89
+ return;
90
+ }
91
+ // fire and forget the log
92
+ this.client
93
+ .putLog({
94
+ stepRunId,
95
+ createdAt,
96
+ message: log,
97
+ level: level || LogLevel.INFO,
98
+ })
99
+ .catch((e) => {
100
+ // log a warning, but this is not a fatal error
101
+ this.logger.warn(`Could not put log: ${e.message}`);
102
+ });
101
103
  }
102
104
  putStream(stepRunId, data) {
103
105
  const createdAt = new Date();
@@ -38,8 +38,6 @@ const events_1 = require("events");
38
38
  const dispatcher_1 = require("../../protoc/dispatcher");
39
39
  const abort_controller_x_1 = require("abort-controller-x");
40
40
  const sleep_1 = __importDefault(require("../../util/sleep"));
41
- const DEFAULT_EVENT_LISTENER_RETRY_INTERVAL = 5; // seconds
42
- const DEFAULT_EVENT_LISTENER_RETRY_COUNT = 20;
43
41
  class Streamable {
44
42
  constructor(listener, id) {
45
43
  this.responseEmitter = new events_1.EventEmitter();
@@ -71,11 +69,13 @@ class GrpcPooledListener {
71
69
  init() {
72
70
  return __awaiter(this, arguments, void 0, function* (retries = 0) {
73
71
  var _a, e_1, _b, _c;
74
- if (retries > DEFAULT_EVENT_LISTENER_RETRY_COUNT)
75
- return;
72
+ let retryCount = retries;
73
+ const MAX_RETRY_INTERVAL = 5000; // 5 seconds in milliseconds
74
+ const BASE_RETRY_INTERVAL = 100; // 0.1 seconds in milliseconds
76
75
  if (retries > 0) {
77
- this.client.logger.info(`Retrying in ... ${DEFAULT_EVENT_LISTENER_RETRY_INTERVAL} seconds`);
78
- yield (0, sleep_1.default)(DEFAULT_EVENT_LISTENER_RETRY_INTERVAL * 1000);
76
+ const backoffTime = Math.min(BASE_RETRY_INTERVAL * 2 ** (retries - 1), MAX_RETRY_INTERVAL);
77
+ this.client.logger.info(`Retrying in ... ${backoffTime / 1000} seconds`);
78
+ yield (0, sleep_1.default)(backoffTime);
79
79
  }
80
80
  try {
81
81
  this.client.logger.debug('Initializing child-listener');
@@ -90,17 +90,12 @@ class GrpcPooledListener {
90
90
  _c = _f.value;
91
91
  _d = false;
92
92
  const event = _c;
93
+ retryCount = 0;
93
94
  const emitter = this.subscribers[event.workflowRunId];
94
95
  if (emitter) {
95
96
  emitter.responseEmitter.emit('response', event);
96
97
  if (event.eventType === dispatcher_1.WorkflowRunEventType.WORKFLOW_RUN_EVENT_TYPE_FINISHED) {
97
98
  delete this.subscribers[event.workflowRunId];
98
- if (Object.keys(this.subscribers).length === 0) {
99
- // FIXME it would be better to cleanup on parent complete
100
- this.client.logger.debug('All subscriptions finished, cleaning up listener');
101
- this.signal.abort();
102
- this.onFinish();
103
- }
104
99
  }
105
100
  }
106
101
  }
@@ -124,10 +119,9 @@ class GrpcPooledListener {
124
119
  finally {
125
120
  // it is possible the server hangs up early,
126
121
  // restart the listener if we still have subscribers
127
- this.client.logger.debug('Child listener finally');
128
- if (Object.keys(this.subscribers).length !== 0) {
129
- this.init(retries + 1);
130
- }
122
+ this.client.logger.debug(`Child listener loop exited with ${Object.keys(this.subscribers).length} subscribers`);
123
+ this.client.logger.debug(`Restarting child listener retry ${retryCount + 1}`);
124
+ this.init(retryCount + 1);
131
125
  }
132
126
  });
133
127
  }
@@ -79,15 +79,13 @@ class WebhookHandler {
79
79
  expressHandler({ secret }) {
80
80
  return (req, res) => {
81
81
  if (req.method === 'GET') {
82
- res.sendStatus(200);
83
- res.send(okMessage);
82
+ res.sendStatus(200).send(okMessage);
84
83
  return;
85
84
  }
86
85
  if (req.method === 'PUT') {
87
86
  this.getHealthcheckResponse(req.body, req.headers['x-hatchet-signature'], secret)
88
87
  .then((resp) => {
89
- res.sendStatus(200);
90
- res.json(resp);
88
+ res.sendStatus(200).json(resp);
91
89
  })
92
90
  .catch((err) => {
93
91
  res.sendStatus(500);
@@ -96,11 +94,14 @@ class WebhookHandler {
96
94
  return;
97
95
  }
98
96
  if (req.method !== 'POST') {
99
- res.sendStatus(405);
100
- res.json({ error: 'Method not allowed' });
97
+ res.sendStatus(405).json({ error: 'Method not allowed' });
101
98
  return;
102
99
  }
103
- this.handle(req.body, req.headers['x-hatchet-signature'], secret)
100
+ let action = req.body;
101
+ if (typeof action !== 'string') {
102
+ action = JSON.stringify(action);
103
+ }
104
+ this.handle(action, req.headers['x-hatchet-signature'], secret)
104
105
  .then(() => {
105
106
  res.sendStatus(200);
106
107
  })
@@ -13,36 +13,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const sdk_1 = __importDefault(require("../sdk"));
16
- const hatchet = sdk_1.default.init({
17
- log_level: 'OFF',
18
- });
19
- const sleep = (ms) => new Promise((resolve) => {
20
- setTimeout(resolve, ms);
21
- });
16
+ const hatchet = sdk_1.default.init();
17
+ // ❓ OnFailure Step
18
+ // This workflow will fail because the step will throw an error
19
+ // we define an onFailure step to handle this case
22
20
  const workflow = {
21
+ // ... normal workflow definition
23
22
  id: 'on-failure-example',
24
23
  description: 'test',
25
24
  on: {
26
25
  event: 'user:create',
27
26
  },
27
+ // ,
28
28
  steps: [
29
29
  {
30
- name: 'dag-step1',
30
+ name: 'step1',
31
31
  run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
32
- console.log('Starting Step 1!');
33
- yield sleep(1000);
32
+ // 👀 this step will always throw an error
34
33
  throw new Error('Step 1 failed');
35
34
  }),
36
35
  },
37
36
  ],
37
+ // 👀 After the workflow fails, this special step will run
38
38
  onFailure: {
39
39
  name: 'on-failure-step',
40
40
  run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
41
- console.log('Starting On Failure Step!');
41
+ // 👀 we can do things like perform cleanup logic
42
+ // or notify a user here
42
43
  return { onFailure: 'step' };
43
44
  }),
44
45
  },
45
46
  };
47
+ // ‼️
48
+ // ❓ OnFailure With Details
49
+ // Coming soon to TypeScript! https://github.com/hatchet-dev/hatchet-typescript/issues/447
50
+ // ‼️
46
51
  function main() {
47
52
  return __awaiter(this, void 0, void 0, function* () {
48
53
  const worker = yield hatchet.worker('example-worker', 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatchet-dev/typescript-sdk",
3
- "version": "0.15.1-alpha6",
3
+ "version": "0.15.2",
4
4
  "description": "Background task orchestration & visibility for developers",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -17,7 +17,8 @@
17
17
  "scripts": {
18
18
  "build": "echo 'build hatchet sdk with `npn run tsc:build` to ensure it is not build during the publish step' && exit 0",
19
19
  "prepare": "npm run build",
20
- "tsc:build": "tsc && resolve-tspaths",
20
+ "dump-version": "node -e \"console.log('export const HATCHET_VERSION = \\'' + require('./package.json').version + '\\';');\" > src/version.ts",
21
+ "tsc:build": "npm run dump-version && tsc && resolve-tspaths",
21
22
  "test:unit": "jest --testMatch='**/*.test.ts'",
22
23
  "test:e2e": "jest --testMatch='**/*.e2e.ts'",
23
24
  "test:unit:watch": "jest --testMatch='**/*.test.ts' --watch",
@@ -57,8 +58,8 @@
57
58
  "worker:logger": "npm run exec -- ./src/examples/logger.ts",
58
59
  "api": "npm run exec -- ./src/examples/api.ts",
59
60
  "prepublish": "cp package.json dist/package.json;",
60
- "publish:ci": "rm -rf ./dist && npm run tsc:build && npm run prepublish && cd dist && npm publish --access public --no-git-checks",
61
- "publish:ci:alpha": "rm -rf ./dist && npm run tsc:build && npm run prepublish && cd dist && npm publish --access public --no-git-checks --tag alpha",
61
+ "publish:ci": "rm -rf ./dist && npm run dump-version && npm run tsc:build && npm run prepublish && cd dist && npm publish --access public --no-git-checks",
62
+ "publish:ci:alpha": "rm -rf ./dist && npm run dump-version && npm run tsc:build && npm run prepublish && cd dist && npm publish --access public --no-git-checks --tag alpha",
62
63
  "generate-docs": "typedoc"
63
64
  },
64
65
  "keywords": [],
@@ -1,6 +1,15 @@
1
1
  import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire';
2
2
  import { type CallContext, type CallOptions } from 'nice-grpc-common';
3
3
  export declare const protobufPackage = "";
4
+ export declare enum SDKS {
5
+ UNKNOWN = 0,
6
+ GO = 1,
7
+ PYTHON = 2,
8
+ TYPESCRIPT = 3,
9
+ UNRECOGNIZED = -1
10
+ }
11
+ export declare function sDKSFromJSON(object: any): SDKS;
12
+ export declare function sDKSToJSON(object: SDKS): string;
4
13
  export declare enum ActionType {
5
14
  START_STEP_RUN = 0,
6
15
  CANCEL_STEP_RUN = 1,
@@ -59,6 +68,13 @@ export interface WorkerLabels {
59
68
  strValue?: string | undefined;
60
69
  intValue?: number | undefined;
61
70
  }
71
+ export interface RuntimeInfo {
72
+ sdkVersion?: string | undefined;
73
+ language?: SDKS | undefined;
74
+ languageVersion?: string | undefined;
75
+ os?: string | undefined;
76
+ extra?: string | undefined;
77
+ }
62
78
  export interface WorkerRegisterRequest {
63
79
  /** the name of the worker */
64
80
  workerName: string;
@@ -74,6 +90,8 @@ export interface WorkerRegisterRequest {
74
90
  };
75
91
  /** (optional) webhookId is the id of the webhook that the worker is associated with (if any) */
76
92
  webhookId?: string | undefined;
93
+ /** (optional) information regarding the runtime environment of the worker */
94
+ runtimeInfo?: RuntimeInfo | undefined;
77
95
  }
78
96
  export interface WorkerRegisterRequest_LabelsEntry {
79
97
  key: string;
@@ -274,6 +292,7 @@ export interface ReleaseSlotRequest {
274
292
  export interface ReleaseSlotResponse {
275
293
  }
276
294
  export declare const WorkerLabels: MessageFns<WorkerLabels>;
295
+ export declare const RuntimeInfo: MessageFns<RuntimeInfo>;
277
296
  export declare const WorkerRegisterRequest: MessageFns<WorkerRegisterRequest>;
278
297
  export declare const WorkerRegisterRequest_LabelsEntry: MessageFns<WorkerRegisterRequest_LabelsEntry>;
279
298
  export declare const WorkerRegisterResponse: MessageFns<WorkerRegisterResponse>;