@hatchet-dev/typescript-sdk 0.0.1 → 0.0.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.
- package/dist/{hatchet/clients → clients}/admin/admin-client.d.ts +2 -2
- package/dist/{hatchet/clients → clients}/admin/admin-client.js +2 -2
- package/dist/{hatchet/clients → clients}/dispatcher/action-listener.d.ts +3 -3
- package/dist/{hatchet/clients → clients}/dispatcher/action-listener.js +2 -2
- package/dist/{hatchet/clients → clients}/dispatcher/action-listener.test.d.ts +1 -1
- package/dist/{hatchet/clients → clients}/dispatcher/action-listener.test.js +2 -2
- package/dist/{hatchet/clients → clients}/dispatcher/dispatcher-client.d.ts +3 -3
- package/dist/{hatchet/clients → clients}/dispatcher/dispatcher-client.js +2 -2
- package/dist/{hatchet/clients → clients}/dispatcher/dispatcher-client.test.js +1 -1
- package/dist/{hatchet/clients → clients}/event/event-client.d.ts +3 -3
- package/dist/{hatchet/clients → clients}/event/event-client.js +2 -2
- package/dist/{hatchet/clients → clients}/event/event-client.test.js +1 -1
- package/dist/{hatchet/clients → clients}/hatchet-client/hatchet-client.d.ts +4 -4
- package/dist/{hatchet/clients → clients}/hatchet-client/hatchet-client.js +5 -5
- package/dist/{hatchet/clients → clients}/worker/worker.d.ts +4 -4
- package/dist/{hatchet/clients → clients}/worker/worker.js +3 -3
- package/dist/{hatchet/clients → clients}/worker/worker.test.js +5 -5
- package/dist/index.d.ts +2 -0
- package/dist/{hatchet/index.js → index.js} +1 -1
- package/dist/protoc/events/index.js +17 -0
- package/dist/sdk.d.ts +2 -0
- package/dist/{hatchet/sdk.js → sdk.js} +1 -1
- package/dist/{hatchet/step.js → step.js} +1 -1
- package/dist/{hatchet/util → util}/config-loader/config-loader.d.ts +1 -1
- package/dist/{hatchet/util → util}/config-loader/config-loader.js +1 -1
- package/package.json +6 -5
- package/.eslintrc.json +0 -36
- package/.prettierrc.json +0 -6
- package/dist/hatchet/index.d.ts +0 -2
- package/dist/hatchet/sdk.d.ts +0 -2
- package/examples/dag-worker.ts +0 -55
- package/examples/example-event.ts +0 -7
- package/examples/simple-worker.ts +0 -39
- package/generate-protoc.sh +0 -10
- package/hatchet/clients/admin/admin-client.test.ts +0 -116
- package/hatchet/clients/admin/admin-client.ts +0 -43
- package/hatchet/clients/dispatcher/action-listener.test.ts +0 -270
- package/hatchet/clients/dispatcher/action-listener.ts +0 -91
- package/hatchet/clients/dispatcher/dispatcher-client.test.ts +0 -111
- package/hatchet/clients/dispatcher/dispatcher-client.ts +0 -47
- package/hatchet/clients/event/event-client.test.ts +0 -72
- package/hatchet/clients/event/event-client.ts +0 -32
- package/hatchet/clients/hatchet-client/client-config.ts +0 -22
- package/hatchet/clients/hatchet-client/fixtures/.hatchet-invalid.yaml +0 -6
- package/hatchet/clients/hatchet-client/fixtures/.hatchet.yaml +0 -8
- package/hatchet/clients/hatchet-client/hatchet-client.test.ts +0 -162
- package/hatchet/clients/hatchet-client/hatchet-client.ts +0 -136
- package/hatchet/clients/hatchet-client/index.ts +0 -2
- package/hatchet/clients/worker/index.ts +0 -1
- package/hatchet/clients/worker/worker.test.ts +0 -347
- package/hatchet/clients/worker/worker.ts +0 -229
- package/hatchet/index.ts +0 -3
- package/hatchet/sdk.ts +0 -3
- package/hatchet/step.ts +0 -48
- package/hatchet/util/config-loader/config-loader.test.ts +0 -79
- package/hatchet/util/config-loader/config-loader.ts +0 -91
- package/hatchet/util/config-loader/fixtures/.hatchet-invalid.yaml +0 -6
- package/hatchet/util/config-loader/fixtures/.hatchet.yaml +0 -8
- package/hatchet/util/config-loader/index.ts +0 -1
- package/hatchet/util/errors/hatchet-error.ts +0 -8
- package/hatchet/util/hatchet-promise/hatchet-promise.test.ts +0 -32
- package/hatchet/util/hatchet-promise/hatchet-promise.ts +0 -13
- package/hatchet/util/logger/index.ts +0 -1
- package/hatchet/util/logger/logger.ts +0 -44
- package/hatchet/util/sleep.ts +0 -6
- package/hatchet/workflow.ts +0 -30
- package/jest.config.ts +0 -205
- package/protoc/dispatcher/dispatcher.ts +0 -1101
- package/protoc/dispatcher/index.ts +0 -1
- package/protoc/events/events.ts +0 -519
- package/protoc/google/protobuf/timestamp.ts +0 -210
- package/protoc/google/protobuf/wrappers.ts +0 -657
- package/protoc/workflows/index.ts +0 -1
- package/protoc/workflows/workflows.ts +0 -2158
- package/tsconfig.json +0 -120
- /package/dist/{hatchet/clients → clients}/admin/admin-client.test.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/admin/admin-client.test.js +0 -0
- /package/dist/{hatchet/clients → clients}/dispatcher/dispatcher-client.test.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/event/event-client.test.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/hatchet-client/client-config.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/hatchet-client/client-config.js +0 -0
- /package/dist/{hatchet/clients → clients}/hatchet-client/hatchet-client.test.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/hatchet-client/hatchet-client.test.js +0 -0
- /package/dist/{hatchet/clients → clients}/hatchet-client/index.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/hatchet-client/index.js +0 -0
- /package/dist/{hatchet/clients → clients}/worker/index.d.ts +0 -0
- /package/dist/{hatchet/clients → clients}/worker/index.js +0 -0
- /package/dist/{hatchet/clients → clients}/worker/worker.test.d.ts +0 -0
- /package/{protoc/events/index.ts → dist/protoc/events/index.d.ts} +0 -0
- /package/dist/{hatchet/step.d.ts → step.d.ts} +0 -0
- /package/dist/{hatchet/util → util}/config-loader/config-loader.test.d.ts +0 -0
- /package/dist/{hatchet/util → util}/config-loader/config-loader.test.js +0 -0
- /package/dist/{hatchet/util → util}/config-loader/index.d.ts +0 -0
- /package/dist/{hatchet/util → util}/config-loader/index.js +0 -0
- /package/dist/{hatchet/util → util}/errors/hatchet-error.d.ts +0 -0
- /package/dist/{hatchet/util → util}/errors/hatchet-error.js +0 -0
- /package/dist/{hatchet/util → util}/hatchet-promise/hatchet-promise.d.ts +0 -0
- /package/dist/{hatchet/util → util}/hatchet-promise/hatchet-promise.js +0 -0
- /package/dist/{hatchet/util → util}/hatchet-promise/hatchet-promise.test.d.ts +0 -0
- /package/dist/{hatchet/util → util}/hatchet-promise/hatchet-promise.test.js +0 -0
- /package/dist/{hatchet/util → util}/logger/index.d.ts +0 -0
- /package/dist/{hatchet/util → util}/logger/index.js +0 -0
- /package/dist/{hatchet/util → util}/logger/logger.d.ts +0 -0
- /package/dist/{hatchet/util → util}/logger/logger.js +0 -0
- /package/dist/{hatchet/util → util}/sleep.d.ts +0 -0
- /package/dist/{hatchet/util → util}/sleep.js +0 -0
- /package/dist/{hatchet/workflow.d.ts → workflow.d.ts} +0 -0
- /package/dist/{hatchet/workflow.js → workflow.js} +0 -0
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { ChannelCredentials, createChannel, createClientFactory } from 'nice-grpc';
|
|
2
|
-
import { HatchetClient } from './hatchet-client';
|
|
3
|
-
|
|
4
|
-
export const mockChannel = createChannel('localhost:50051');
|
|
5
|
-
export const mockFactory = createClientFactory();
|
|
6
|
-
|
|
7
|
-
describe('Client', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
process.env.HATCHET_CLIENT_TOKEN = 'TOKEN_ENV';
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('should load from environment variables', () => {
|
|
13
|
-
const hatchet = new HatchetClient(
|
|
14
|
-
{
|
|
15
|
-
token: 'TOKEN_ENV',
|
|
16
|
-
host_port: 'HOST_PORT',
|
|
17
|
-
log_level: 'OFF',
|
|
18
|
-
tls_config: {
|
|
19
|
-
cert_file: 'TLS_CERT_FILE',
|
|
20
|
-
key_file: 'TLS_KEY_FILE',
|
|
21
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
22
|
-
server_name: 'TLS_SERVER_NAME',
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
credentials: ChannelCredentials.createInsecure(),
|
|
27
|
-
}
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
expect(hatchet.config).toEqual({
|
|
31
|
-
token: 'TOKEN_ENV',
|
|
32
|
-
host_port: 'HOST_PORT',
|
|
33
|
-
log_level: 'OFF',
|
|
34
|
-
tls_config: {
|
|
35
|
-
tls_strategy: 'tls',
|
|
36
|
-
cert_file: 'TLS_CERT_FILE',
|
|
37
|
-
key_file: 'TLS_KEY_FILE',
|
|
38
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
39
|
-
server_name: 'TLS_SERVER_NAME',
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should throw an error if the config param is invalid', () => {
|
|
45
|
-
expect(
|
|
46
|
-
() =>
|
|
47
|
-
new HatchetClient({
|
|
48
|
-
host_port: 'HOST_PORT',
|
|
49
|
-
tls_config: {
|
|
50
|
-
tls_strategy: 'tls',
|
|
51
|
-
cert_file: 'TLS_CERT_FILE',
|
|
52
|
-
key_file: 'TLS_KEY_FILE',
|
|
53
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
54
|
-
// @ts-ignore
|
|
55
|
-
server_name: undefined,
|
|
56
|
-
},
|
|
57
|
-
})
|
|
58
|
-
).toThrow();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should favor config param over yaml over env vars ', () => {
|
|
62
|
-
const hatchet = new HatchetClient(
|
|
63
|
-
{
|
|
64
|
-
tls_config: {
|
|
65
|
-
cert_file: 'TLS_CERT_FILE',
|
|
66
|
-
key_file: 'TLS_KEY_FILE',
|
|
67
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
68
|
-
server_name: 'TLS_SERVER_NAME',
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
config_path: './fixtures/.hatchet.yaml',
|
|
73
|
-
credentials: ChannelCredentials.createInsecure(),
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
expect(hatchet.config).toEqual({
|
|
78
|
-
token: 'TOKEN_YAML',
|
|
79
|
-
host_port: 'HOST_PORT_YAML',
|
|
80
|
-
log_level: 'INFO',
|
|
81
|
-
tls_config: {
|
|
82
|
-
tls_strategy: 'tls',
|
|
83
|
-
cert_file: 'TLS_CERT_FILE',
|
|
84
|
-
key_file: 'TLS_KEY_FILE',
|
|
85
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
86
|
-
server_name: 'TLS_SERVER_NAME',
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe('with_host_port', () => {
|
|
92
|
-
it('should set the host_port', () => {
|
|
93
|
-
const hatchet = HatchetClient.with_host_port(
|
|
94
|
-
'HOST',
|
|
95
|
-
1234,
|
|
96
|
-
{
|
|
97
|
-
token: 'TOKEN',
|
|
98
|
-
tls_config: {
|
|
99
|
-
tls_strategy: 'tls',
|
|
100
|
-
cert_file: 'TLS_CERT_FILE',
|
|
101
|
-
key_file: 'TLS_KEY_FILE',
|
|
102
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
103
|
-
server_name: 'TLS_SERVER_NAME',
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
credentials: ChannelCredentials.createInsecure(),
|
|
108
|
-
}
|
|
109
|
-
);
|
|
110
|
-
expect(hatchet.config).toEqual({
|
|
111
|
-
token: 'TOKEN',
|
|
112
|
-
host_port: 'HOST:1234',
|
|
113
|
-
log_level: 'INFO',
|
|
114
|
-
tls_config: {
|
|
115
|
-
tls_strategy: 'tls',
|
|
116
|
-
cert_file: 'TLS_CERT_FILE',
|
|
117
|
-
key_file: 'TLS_KEY_FILE',
|
|
118
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
119
|
-
server_name: 'TLS_SERVER_NAME',
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
describe('Worker', () => {
|
|
126
|
-
let hatchet: HatchetClient;
|
|
127
|
-
|
|
128
|
-
beforeEach(() => {
|
|
129
|
-
hatchet = new HatchetClient(
|
|
130
|
-
{
|
|
131
|
-
token: 'TOKEN',
|
|
132
|
-
host_port: 'HOST_PORT',
|
|
133
|
-
log_level: 'OFF',
|
|
134
|
-
tls_config: {
|
|
135
|
-
cert_file: 'TLS_CERT_FILE',
|
|
136
|
-
key_file: 'TLS_KEY_FILE',
|
|
137
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
138
|
-
server_name: 'TLS_SERVER_NAME',
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
credentials: ChannelCredentials.createInsecure(),
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('run', () => {
|
|
148
|
-
xit('should start a worker', () => {
|
|
149
|
-
const worker = hatchet.run('workflow1');
|
|
150
|
-
expect(worker).toBeDefined();
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe('worker', () => {
|
|
155
|
-
it('should start a worker', () => {
|
|
156
|
-
const worker = hatchet.worker('workflow1');
|
|
157
|
-
|
|
158
|
-
expect(worker).toBeDefined();
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { ConfigLoader } from '@util/config-loader';
|
|
3
|
-
import { EventClient } from '@clients/event/event-client';
|
|
4
|
-
import { DispatcherClient } from '@clients/dispatcher/dispatcher-client';
|
|
5
|
-
import { AdminClient } from '@clients/admin/admin-client';
|
|
6
|
-
import {
|
|
7
|
-
CallOptions,
|
|
8
|
-
Channel,
|
|
9
|
-
ChannelCredentials,
|
|
10
|
-
ClientMiddlewareCall,
|
|
11
|
-
Metadata,
|
|
12
|
-
createChannel,
|
|
13
|
-
createClientFactory,
|
|
14
|
-
} from 'nice-grpc';
|
|
15
|
-
import { Workflow } from '@hatchet/workflow';
|
|
16
|
-
import { Worker } from '@clients/worker';
|
|
17
|
-
import Logger from '@hatchet/util/logger/logger';
|
|
18
|
-
import { ClientConfig, ClientConfigSchema } from './client-config';
|
|
19
|
-
|
|
20
|
-
export interface HatchetClientOptions {
|
|
21
|
-
config_path?: string;
|
|
22
|
-
credentials?: ChannelCredentials;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const addTokenMiddleware = (token: string) =>
|
|
26
|
-
async function* _<Request, Response>(
|
|
27
|
-
call: ClientMiddlewareCall<Request, Response>,
|
|
28
|
-
options: CallOptions
|
|
29
|
-
) {
|
|
30
|
-
const optionsWithAuth: CallOptions = {
|
|
31
|
-
...options,
|
|
32
|
-
metadata: new Metadata({ authorization: `bearer ${token}` }),
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (!call.responseStream) {
|
|
36
|
-
const response = yield* call.next(call.request, optionsWithAuth);
|
|
37
|
-
|
|
38
|
-
return response;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
for await (const response of call.next(call.request, optionsWithAuth)) {
|
|
42
|
-
yield response;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return undefined;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export class HatchetClient {
|
|
49
|
-
config: ClientConfig;
|
|
50
|
-
credentials: ChannelCredentials;
|
|
51
|
-
channel: Channel;
|
|
52
|
-
|
|
53
|
-
event: EventClient;
|
|
54
|
-
dispatcher: DispatcherClient;
|
|
55
|
-
admin: AdminClient;
|
|
56
|
-
|
|
57
|
-
logger: Logger;
|
|
58
|
-
|
|
59
|
-
constructor(config?: Partial<ClientConfig>, options?: HatchetClientOptions) {
|
|
60
|
-
// Initializes a new Client instance.
|
|
61
|
-
// Loads config in the following order: config param > yaml file > env vars
|
|
62
|
-
|
|
63
|
-
const loaded = ConfigLoader.load_client_config({
|
|
64
|
-
path: options?.config_path,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const valid = ClientConfigSchema.parse({
|
|
69
|
-
...loaded,
|
|
70
|
-
...{ ...config, tls_config: { ...loaded.tls_config, ...config?.tls_config } },
|
|
71
|
-
});
|
|
72
|
-
this.config = valid;
|
|
73
|
-
} catch (e) {
|
|
74
|
-
if (e instanceof z.ZodError) {
|
|
75
|
-
throw new Error(`Invalid client config: ${e.message}`);
|
|
76
|
-
}
|
|
77
|
-
throw e;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
this.credentials =
|
|
81
|
-
options?.credentials ?? ConfigLoader.createCredentials(this.config.tls_config);
|
|
82
|
-
|
|
83
|
-
this.channel = createChannel(this.config.host_port, this.credentials, {
|
|
84
|
-
'grpc.ssl_target_name_override': this.config.tls_config.server_name,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const clientFactory = createClientFactory().use(addTokenMiddleware(this.config.token));
|
|
88
|
-
|
|
89
|
-
this.event = new EventClient(this.config, this.channel, clientFactory);
|
|
90
|
-
this.dispatcher = new DispatcherClient(this.config, this.channel, clientFactory);
|
|
91
|
-
this.admin = new AdminClient(this.config, this.channel, clientFactory);
|
|
92
|
-
|
|
93
|
-
this.logger = new Logger('HatchetClient', this.config.log_level);
|
|
94
|
-
|
|
95
|
-
this.logger.info(`Initialized HatchetClient`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
static with_host_port(
|
|
99
|
-
host: string,
|
|
100
|
-
port: number,
|
|
101
|
-
config?: Partial<ClientConfig>,
|
|
102
|
-
options?: HatchetClientOptions
|
|
103
|
-
): HatchetClient {
|
|
104
|
-
return new HatchetClient(
|
|
105
|
-
{
|
|
106
|
-
...config,
|
|
107
|
-
host_port: `${host}:${port}`,
|
|
108
|
-
},
|
|
109
|
-
options
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
static init(config?: Partial<ClientConfig>, options?: HatchetClientOptions): HatchetClient {
|
|
114
|
-
return new HatchetClient(config, options);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async run(workflow: string | Workflow): Promise<Worker> {
|
|
118
|
-
const worker = await this.worker(workflow);
|
|
119
|
-
worker.start();
|
|
120
|
-
return worker;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async worker(workflow: string | Workflow): Promise<Worker> {
|
|
124
|
-
const name = typeof workflow === 'string' ? workflow : workflow.id;
|
|
125
|
-
const worker = new Worker(this, {
|
|
126
|
-
name,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
if (typeof workflow !== 'string') {
|
|
130
|
-
await worker.register_workflow(workflow);
|
|
131
|
-
return worker;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return worker;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './worker';
|
|
@@ -1,347 +0,0 @@
|
|
|
1
|
-
import { HatchetClient } from '@clients/hatchet-client';
|
|
2
|
-
import { ActionEventType, ActionType, AssignedAction } from '@protoc/dispatcher';
|
|
3
|
-
import { ActionListener } from '@clients/dispatcher/action-listener';
|
|
4
|
-
import { ServerError, Status } from 'nice-grpc-common';
|
|
5
|
-
import { mockListener } from '@clients/dispatcher/action-listener.test';
|
|
6
|
-
import { never } from 'zod';
|
|
7
|
-
import sleep from '@util/sleep';
|
|
8
|
-
import { ChannelCredentials } from 'nice-grpc';
|
|
9
|
-
import { Worker } from './worker';
|
|
10
|
-
import { Context } from '@hatchet/step';
|
|
11
|
-
|
|
12
|
-
type AssignActionMock = AssignedAction | Error;
|
|
13
|
-
|
|
14
|
-
const mockStart: AssignActionMock = {
|
|
15
|
-
tenantId: 'TENANT_ID',
|
|
16
|
-
jobId: 'job1',
|
|
17
|
-
jobName: 'Job One',
|
|
18
|
-
jobRunId: 'run1',
|
|
19
|
-
stepId: 'step1',
|
|
20
|
-
stepRunId: 'runStep1',
|
|
21
|
-
actionId: 'action1',
|
|
22
|
-
actionType: ActionType.START_STEP_RUN,
|
|
23
|
-
actionPayload: JSON.stringify('{"input": {"data": 1}}'),
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const mockCancel: AssignActionMock = {
|
|
27
|
-
...mockStart,
|
|
28
|
-
actionType: ActionType.CANCEL_STEP_RUN,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
describe('Worker', () => {
|
|
32
|
-
let hatchet: HatchetClient;
|
|
33
|
-
|
|
34
|
-
beforeEach(() => {
|
|
35
|
-
hatchet = new HatchetClient(
|
|
36
|
-
{
|
|
37
|
-
token: 'TOKEN',
|
|
38
|
-
log_level: 'OFF',
|
|
39
|
-
host_port: 'HOST_PORT',
|
|
40
|
-
tls_config: {
|
|
41
|
-
cert_file: 'TLS_CERT_FILE',
|
|
42
|
-
key_file: 'TLS_KEY_FILE',
|
|
43
|
-
ca_file: 'TLS_ROOT_CA_FILE',
|
|
44
|
-
server_name: 'TLS_SERVER_NAME',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
credentials: ChannelCredentials.createInsecure(),
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('register_workflow', () => {
|
|
54
|
-
it('should update the registry', async () => {
|
|
55
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
56
|
-
const putWorkflowSpy = jest.spyOn(worker.client.admin, 'put_workflow').mockResolvedValue();
|
|
57
|
-
|
|
58
|
-
const workflow = {
|
|
59
|
-
id: 'workflow1',
|
|
60
|
-
description: 'test',
|
|
61
|
-
on: {
|
|
62
|
-
event: 'user:create',
|
|
63
|
-
},
|
|
64
|
-
steps: [
|
|
65
|
-
{
|
|
66
|
-
name: 'step1',
|
|
67
|
-
run: (ctx: any) => {
|
|
68
|
-
return { test: 'test' };
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
await worker.register_workflow(workflow);
|
|
75
|
-
|
|
76
|
-
expect(putWorkflowSpy).toHaveBeenCalledTimes(1);
|
|
77
|
-
|
|
78
|
-
expect(worker.action_registry).toEqual({
|
|
79
|
-
[`default:step1`]: workflow.steps[0].run,
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('handle_start_step_run', () => {
|
|
85
|
-
it('should start a step run', async () => {
|
|
86
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
87
|
-
|
|
88
|
-
const putWorkflowSpy = jest.spyOn(worker.client.admin, 'put_workflow').mockResolvedValue();
|
|
89
|
-
|
|
90
|
-
const getActionEventSpy = jest.spyOn(worker, 'get_action_event');
|
|
91
|
-
|
|
92
|
-
const sendActionEventSpy = jest
|
|
93
|
-
.spyOn(worker.client.dispatcher, 'send_action_event')
|
|
94
|
-
.mockResolvedValue({
|
|
95
|
-
tenantId: 'TENANT_ID',
|
|
96
|
-
workerId: 'WORKER_ID',
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const startSpy = jest.fn().mockReturnValue({ data: 4 });
|
|
100
|
-
|
|
101
|
-
worker.action_registry = {
|
|
102
|
-
[mockStart.actionId]: startSpy,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
worker.handle_start_step_run(mockStart);
|
|
106
|
-
await sleep(100);
|
|
107
|
-
|
|
108
|
-
expect(startSpy).toHaveBeenCalledTimes(1);
|
|
109
|
-
|
|
110
|
-
expect(getActionEventSpy).toHaveBeenNthCalledWith(
|
|
111
|
-
2,
|
|
112
|
-
expect.anything(),
|
|
113
|
-
ActionEventType.STEP_EVENT_TYPE_COMPLETED,
|
|
114
|
-
{ data: 4 }
|
|
115
|
-
);
|
|
116
|
-
expect(worker.futures[mockStart.stepRunId]).toBeUndefined();
|
|
117
|
-
expect(sendActionEventSpy).toHaveBeenCalledTimes(2);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should fail gracefully', async () => {
|
|
121
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
122
|
-
|
|
123
|
-
const getActionEventSpy = jest.spyOn(worker, 'get_action_event');
|
|
124
|
-
|
|
125
|
-
const sendActionEventSpy = jest
|
|
126
|
-
.spyOn(worker.client.dispatcher, 'send_action_event')
|
|
127
|
-
.mockResolvedValue({
|
|
128
|
-
tenantId: 'TENANT_ID',
|
|
129
|
-
workerId: 'WORKER_ID',
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const startSpy = jest.fn().mockRejectedValue(new Error('ERROR'));
|
|
133
|
-
|
|
134
|
-
worker.action_registry = {
|
|
135
|
-
[mockStart.actionId]: startSpy,
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
worker.handle_start_step_run(mockStart);
|
|
139
|
-
await sleep(100);
|
|
140
|
-
|
|
141
|
-
expect(startSpy).toHaveBeenCalledTimes(1);
|
|
142
|
-
expect(getActionEventSpy).toHaveBeenNthCalledWith(
|
|
143
|
-
2,
|
|
144
|
-
expect.anything(),
|
|
145
|
-
ActionEventType.STEP_EVENT_TYPE_FAILED,
|
|
146
|
-
expect.anything()
|
|
147
|
-
);
|
|
148
|
-
expect(worker.futures[mockStart.stepRunId]).toBeUndefined();
|
|
149
|
-
expect(sendActionEventSpy).toHaveBeenCalledTimes(2);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
describe('handle_cancel_step_run', () => {
|
|
154
|
-
it('should cancel a step run', () => {
|
|
155
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
156
|
-
|
|
157
|
-
const cancelSpy = jest.fn().mockReturnValue(undefined);
|
|
158
|
-
|
|
159
|
-
worker.futures = {
|
|
160
|
-
[mockCancel.stepRunId]: {
|
|
161
|
-
cancel: cancelSpy,
|
|
162
|
-
} as any,
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
worker.handle_cancel_step_run(mockCancel);
|
|
166
|
-
|
|
167
|
-
expect(cancelSpy).toHaveBeenCalledTimes(1);
|
|
168
|
-
expect(worker.futures[mockCancel.stepRunId]).toBeUndefined();
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe('exit_gracefully', () => {
|
|
173
|
-
xit('should call exit_gracefully on SIGTERM', async () => {
|
|
174
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
175
|
-
|
|
176
|
-
// the spy is not working and the test is killing the test process
|
|
177
|
-
const exitSpy = jest.spyOn(worker, 'exit_gracefully').mockImplementationOnce(() => {
|
|
178
|
-
throw new Error('Simulated error');
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
process.emit('SIGTERM', 'SIGTERM');
|
|
182
|
-
expect(exitSpy).toHaveBeenCalledTimes(1);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
xit('should call exit_gracefully on SIGINT', async () => {
|
|
186
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
187
|
-
|
|
188
|
-
// This is killing the process (as it should) fix the spy at some point
|
|
189
|
-
const exitSpy = jest.spyOn(worker, 'exit_gracefully').mockResolvedValue();
|
|
190
|
-
|
|
191
|
-
process.emit('SIGINT', 'SIGINT');
|
|
192
|
-
expect(exitSpy).toHaveBeenCalledTimes(1);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
xit('should unregister the listener and exit', async () => {
|
|
196
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
197
|
-
|
|
198
|
-
jest.spyOn(process, 'exit').mockImplementation((number) => {
|
|
199
|
-
throw new Error(`EXIT ${number}`);
|
|
200
|
-
}); // This is killing the process (as it should) fix the spy at some point
|
|
201
|
-
|
|
202
|
-
const mockActionListener = new ActionListener(
|
|
203
|
-
hatchet.dispatcher,
|
|
204
|
-
mockListener([mockStart, mockStart, new ServerError(Status.CANCELLED, 'CANCELLED')]),
|
|
205
|
-
'WORKER_ID'
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
mockActionListener.unregister = jest.fn().mockResolvedValue(never());
|
|
209
|
-
worker.listener = mockActionListener;
|
|
210
|
-
|
|
211
|
-
expect(async () => {
|
|
212
|
-
await worker.exit_gracefully();
|
|
213
|
-
}).toThrow('EXIT 0');
|
|
214
|
-
expect(mockActionListener.unregister).toHaveBeenCalledTimes(1);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('should exit the process if handle_kill is true', async () => {
|
|
218
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
219
|
-
const exitSpy = jest.spyOn(process, 'exit').mockReturnValue(undefined as never);
|
|
220
|
-
await worker.exit_gracefully();
|
|
221
|
-
expect(exitSpy).toHaveBeenCalledTimes(1);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
describe('start', () => {
|
|
226
|
-
xit('should get actions and start runs', async () => {
|
|
227
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
228
|
-
|
|
229
|
-
const startSpy = jest.spyOn(worker, 'handle_start_step_run').mockReturnValue();
|
|
230
|
-
const cancelSpy = jest.spyOn(worker, 'handle_cancel_step_run').mockReturnValue();
|
|
231
|
-
|
|
232
|
-
const mockActionListener = new ActionListener(
|
|
233
|
-
hatchet.dispatcher,
|
|
234
|
-
mockListener([mockStart, mockStart, new ServerError(Status.CANCELLED, 'CANCELLED')]),
|
|
235
|
-
'WORKER_ID'
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
const getActionListenerSpy = jest
|
|
239
|
-
.spyOn(worker.client.dispatcher, 'get_action_listener')
|
|
240
|
-
.mockResolvedValue(mockActionListener);
|
|
241
|
-
|
|
242
|
-
await worker.start();
|
|
243
|
-
|
|
244
|
-
expect(getActionListenerSpy).toHaveBeenCalledTimes(1);
|
|
245
|
-
expect(startSpy).toHaveBeenCalledTimes(2);
|
|
246
|
-
expect(cancelSpy).toHaveBeenCalledTimes(0);
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('should get actions and cancel runs', async () => {
|
|
250
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
251
|
-
|
|
252
|
-
const startSpy = jest.spyOn(worker, 'handle_start_step_run').mockReturnValue();
|
|
253
|
-
const cancelSpy = jest.spyOn(worker, 'handle_cancel_step_run').mockReturnValue();
|
|
254
|
-
|
|
255
|
-
const mockActionListner = new ActionListener(
|
|
256
|
-
hatchet.dispatcher,
|
|
257
|
-
mockListener([mockStart, mockCancel, new ServerError(Status.CANCELLED, 'CANCELLED')]),
|
|
258
|
-
'WORKER_ID'
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
const getActionListenerSpy = jest
|
|
262
|
-
.spyOn(worker.client.dispatcher, 'get_action_listener')
|
|
263
|
-
.mockResolvedValue(mockActionListner);
|
|
264
|
-
|
|
265
|
-
await worker.start();
|
|
266
|
-
|
|
267
|
-
expect(getActionListenerSpy).toHaveBeenCalledTimes(1);
|
|
268
|
-
expect(startSpy).toHaveBeenCalledTimes(1);
|
|
269
|
-
expect(cancelSpy).toHaveBeenCalledTimes(1);
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('should retry 5 times to start a worker then throw an error', async () => {
|
|
273
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
274
|
-
|
|
275
|
-
const startSpy = jest.spyOn(worker, 'handle_start_step_run').mockReturnValue();
|
|
276
|
-
const cancelSpy = jest.spyOn(worker, 'handle_cancel_step_run').mockReturnValue();
|
|
277
|
-
|
|
278
|
-
const mockActionListner = new ActionListener(
|
|
279
|
-
hatchet.dispatcher,
|
|
280
|
-
mockListener([mockStart, mockCancel, new ServerError(Status.CANCELLED, 'CANCELLED')]),
|
|
281
|
-
'WORKER_ID'
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
const getActionListenerSpy = jest
|
|
285
|
-
.spyOn(worker.client.dispatcher, 'get_action_listener')
|
|
286
|
-
.mockImplementationOnce(() => {
|
|
287
|
-
throw new Error('Simulated error');
|
|
288
|
-
})
|
|
289
|
-
.mockImplementationOnce(() => {
|
|
290
|
-
throw new Error('Simulated error');
|
|
291
|
-
})
|
|
292
|
-
.mockImplementationOnce(() => {
|
|
293
|
-
throw new Error('Simulated error');
|
|
294
|
-
})
|
|
295
|
-
.mockImplementationOnce(() => {
|
|
296
|
-
throw new Error('Simulated error');
|
|
297
|
-
})
|
|
298
|
-
.mockImplementationOnce(() => {
|
|
299
|
-
throw new Error('Simulated error');
|
|
300
|
-
})
|
|
301
|
-
.mockImplementationOnce(() => {
|
|
302
|
-
throw new Error('Simulated error');
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
await worker.start();
|
|
306
|
-
|
|
307
|
-
expect(getActionListenerSpy).toHaveBeenCalledTimes(5);
|
|
308
|
-
expect(startSpy).toHaveBeenCalledTimes(0);
|
|
309
|
-
expect(cancelSpy).toHaveBeenCalledTimes(0);
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('should successfully run after retrying < 5 times', async () => {
|
|
313
|
-
const worker = new Worker(hatchet, { name: 'WORKER_NAME' });
|
|
314
|
-
|
|
315
|
-
const startSpy = jest.spyOn(worker, 'handle_start_step_run').mockReturnValue();
|
|
316
|
-
const cancelSpy = jest.spyOn(worker, 'handle_cancel_step_run').mockReturnValue();
|
|
317
|
-
|
|
318
|
-
const mockActionLister = new ActionListener(
|
|
319
|
-
hatchet.dispatcher,
|
|
320
|
-
mockListener([mockStart, mockCancel, new ServerError(Status.CANCELLED, 'CANCELLED')]),
|
|
321
|
-
'WORKER_ID'
|
|
322
|
-
);
|
|
323
|
-
|
|
324
|
-
const getActionListenerSpy = jest
|
|
325
|
-
.spyOn(worker.client.dispatcher, 'get_action_listener')
|
|
326
|
-
.mockImplementationOnce(() => {
|
|
327
|
-
throw new Error('Simulated error');
|
|
328
|
-
})
|
|
329
|
-
.mockImplementationOnce(() => {
|
|
330
|
-
throw new Error('Simulated error');
|
|
331
|
-
})
|
|
332
|
-
.mockImplementationOnce(() => {
|
|
333
|
-
throw new Error('Simulated error');
|
|
334
|
-
})
|
|
335
|
-
.mockImplementationOnce(() => {
|
|
336
|
-
throw new Error('Simulated error');
|
|
337
|
-
})
|
|
338
|
-
.mockImplementationOnce(async () => mockActionLister);
|
|
339
|
-
|
|
340
|
-
await worker.start();
|
|
341
|
-
|
|
342
|
-
expect(getActionListenerSpy).toHaveBeenCalledTimes(5);
|
|
343
|
-
expect(startSpy).toHaveBeenCalledTimes(1);
|
|
344
|
-
expect(cancelSpy).toHaveBeenCalledTimes(1);
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
});
|