@hatchet-dev/typescript-sdk 1.26.1 → 1.27.0
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/clients/admin/admin-client.js +1 -1
- package/clients/event/event-client.js +12 -12
- package/clients/hatchet-client/client-config.d.ts +11 -0
- package/clients/hatchet-client/client-config.js +7 -1
- package/package.json +1 -1
- package/protoc/v1/workflows.d.ts +10 -1
- package/protoc/v1/workflows.js +51 -3
- package/util/config-loader/config-loader.d.ts +1 -0
- package/util/config-loader/config-loader.js +18 -16
- package/util/retrier.d.ts +10 -1
- package/util/retrier.js +16 -10
- package/v1/client/admin.js +4 -4
- package/v1/client/worker/worker-internal.js +7 -1
- package/v1/examples/idempotency/workflow.d.ts +3 -0
- package/v1/examples/idempotency/workflow.js +14 -1
- package/v1/task.d.ts +13 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -54,14 +54,14 @@ class EventClient {
|
|
|
54
54
|
priority: options.priority,
|
|
55
55
|
scope: options.scope,
|
|
56
56
|
};
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
return this.retrier(() => __awaiter(this, void 0, void 0, function* () { return this.client.push(req); }), this.logger, this.config.retrier)
|
|
58
|
+
.then((result) => {
|
|
59
59
|
this.logger.info(`Event pushed: ${namespacedType}`);
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
|
|
60
|
+
return result;
|
|
61
|
+
})
|
|
62
|
+
.catch((e) => {
|
|
63
63
|
throw (0, hatchet_error_1.toHatchetError)(e);
|
|
64
|
-
}
|
|
64
|
+
});
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
67
|
* @important This method is instrumented by HatchetInstrumentor._patchBulkPushEvent.
|
|
@@ -85,14 +85,14 @@ class EventClient {
|
|
|
85
85
|
const req = {
|
|
86
86
|
events,
|
|
87
87
|
};
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
return this.retrier(() => __awaiter(this, void 0, void 0, function* () { return this.client.bulkPush(req); }), this.logger, this.config.retrier)
|
|
89
|
+
.then((result) => {
|
|
90
90
|
this.logger.info(`Bulk events pushed for type: ${namespacedType}`);
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
91
|
+
return result;
|
|
92
|
+
})
|
|
93
|
+
.catch((e) => {
|
|
94
94
|
throw (0, hatchet_error_1.toHatchetError)(e);
|
|
95
|
-
}
|
|
95
|
+
});
|
|
96
96
|
}
|
|
97
97
|
putLog(taskRunExternalId, log, level, taskRetryCount, metadata) {
|
|
98
98
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -2,6 +2,12 @@ import { ChannelCredentials } from 'nice-grpc';
|
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
import type { Context } from '../../v1/client/worker/context';
|
|
4
4
|
import { Logger, LogLevel } from '../../util/logger';
|
|
5
|
+
export declare const RetrierConfigSchema: z.ZodObject<{
|
|
6
|
+
maxAttempts: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
initialInterval: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
maxJitter: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export type RetrierConfig = z.infer<typeof RetrierConfigSchema>;
|
|
5
11
|
declare const ClientTLSConfigSchema: z.ZodObject<{
|
|
6
12
|
tls_strategy: z.ZodOptional<z.ZodEnum<{
|
|
7
13
|
tls: "tls";
|
|
@@ -60,6 +66,11 @@ export declare const ClientConfigSchema: z.ZodObject<{
|
|
|
60
66
|
cancellation_warning_threshold: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
61
67
|
grpc_max_recv_message_length: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
62
68
|
grpc_max_send_message_length: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
69
|
+
retrier: z.ZodOptional<z.ZodObject<{
|
|
70
|
+
maxAttempts: z.ZodOptional<z.ZodNumber>;
|
|
71
|
+
initialInterval: z.ZodOptional<z.ZodNumber>;
|
|
72
|
+
maxJitter: z.ZodOptional<z.ZodNumber>;
|
|
73
|
+
}, z.core.$strip>>;
|
|
63
74
|
}, z.core.$strip>;
|
|
64
75
|
export type LogConstructor = (context: string, logLevel?: LogLevel) => Logger;
|
|
65
76
|
/**
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ClientConfigSchema = exports.OpenTelemetryConfigSchema = void 0;
|
|
3
|
+
exports.ClientConfigSchema = exports.OpenTelemetryConfigSchema = exports.RetrierConfigSchema = void 0;
|
|
4
4
|
const v4_1 = require("zod/v4");
|
|
5
|
+
exports.RetrierConfigSchema = v4_1.z.object({
|
|
6
|
+
maxAttempts: v4_1.z.number().int().positive().optional(),
|
|
7
|
+
initialInterval: v4_1.z.number().positive().optional(),
|
|
8
|
+
maxJitter: v4_1.z.number().nonnegative().optional(),
|
|
9
|
+
});
|
|
5
10
|
const ClientTLSConfigSchema = v4_1.z.object({
|
|
6
11
|
tls_strategy: v4_1.z.enum(['tls', 'mtls', 'none']).optional(),
|
|
7
12
|
cert_file: v4_1.z.string().optional(),
|
|
@@ -65,4 +70,5 @@ exports.ClientConfigSchema = v4_1.z.object({
|
|
|
65
70
|
.positive()
|
|
66
71
|
.optional()
|
|
67
72
|
.default(4 * 1024 * 1024),
|
|
73
|
+
retrier: exports.RetrierConfigSchema.optional(),
|
|
68
74
|
});
|
package/package.json
CHANGED
package/protoc/v1/workflows.d.ts
CHANGED
|
@@ -45,6 +45,13 @@ export declare enum ConcurrencyLimitStrategy {
|
|
|
45
45
|
}
|
|
46
46
|
export declare function concurrencyLimitStrategyFromJSON(object: any): ConcurrencyLimitStrategy;
|
|
47
47
|
export declare function concurrencyLimitStrategyToJSON(object: ConcurrencyLimitStrategy): string;
|
|
48
|
+
export declare enum IdempotencyMethod {
|
|
49
|
+
TTL = 0,
|
|
50
|
+
STATUS = 1,
|
|
51
|
+
UNRECOGNIZED = -1
|
|
52
|
+
}
|
|
53
|
+
export declare function idempotencyMethodFromJSON(object: any): IdempotencyMethod;
|
|
54
|
+
export declare function idempotencyMethodToJSON(object: IdempotencyMethod): string;
|
|
48
55
|
export interface CancelTasksRequest {
|
|
49
56
|
/** a list of external UUIDs */
|
|
50
57
|
externalIds: string[];
|
|
@@ -136,8 +143,10 @@ export interface CreateWorkflowVersionRequest {
|
|
|
136
143
|
export interface IdempotencyConfig {
|
|
137
144
|
/** a CEL expression for determining the idempotency key for workflow runs */
|
|
138
145
|
expression: string;
|
|
139
|
-
/** time-to-live for idempotency keys in milliseconds */
|
|
146
|
+
/** time-to-live for idempotency keys in milliseconds. if the method is `STATUS`, this is a "fallback" - the longest the key can live before it's evicted */
|
|
140
147
|
ttlMs: number;
|
|
148
|
+
/** the method to use for idempotency, defaults to TTL */
|
|
149
|
+
method?: IdempotencyMethod | undefined;
|
|
141
150
|
}
|
|
142
151
|
export interface IdempotencyCollisionError {
|
|
143
152
|
/** the external ID of the existing workflow run that caused the collision */
|
package/protoc/v1/workflows.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// protoc v3.19.1
|
|
6
6
|
// source: v1/workflows.proto
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.AdminServiceDefinition = exports.GetRunDetailsResponse_TaskRunsEntry = exports.GetRunDetailsResponse = exports.TaskRunDetail = exports.GetRunDetailsRequest = exports.CreateWorkflowVersionResponse = exports.CreateTaskRateLimit = exports.CreateTaskOpts_SlotRequestsEntry = exports.CreateTaskOpts_WorkerLabelsEntry = exports.CreateTaskOpts = exports.Concurrency = exports.DefaultFilter = exports.BulkTriggerIdempotencyCollisionError = exports.IdempotencyCollisionError = exports.IdempotencyConfig = exports.CreateWorkflowVersionRequest = exports.BranchDurableTaskResponse = exports.BranchDurableTaskRequest = exports.TriggerWorkflowRunResponse = exports.TriggerWorkflowRunRequest_DesiredWorkerLabelsEntry = exports.TriggerWorkflowRunRequest = exports.ReplayTasksResponse = exports.CancelTasksResponse = exports.TasksFilter = exports.ReplayTasksRequest = exports.CancelTasksRequest = exports.ConcurrencyLimitStrategy = exports.RunStatus = exports.RateLimitDuration = exports.StickyStrategy = exports.protobufPackage = void 0;
|
|
8
|
+
exports.AdminServiceDefinition = exports.GetRunDetailsResponse_TaskRunsEntry = exports.GetRunDetailsResponse = exports.TaskRunDetail = exports.GetRunDetailsRequest = exports.CreateWorkflowVersionResponse = exports.CreateTaskRateLimit = exports.CreateTaskOpts_SlotRequestsEntry = exports.CreateTaskOpts_WorkerLabelsEntry = exports.CreateTaskOpts = exports.Concurrency = exports.DefaultFilter = exports.BulkTriggerIdempotencyCollisionError = exports.IdempotencyCollisionError = exports.IdempotencyConfig = exports.CreateWorkflowVersionRequest = exports.BranchDurableTaskResponse = exports.BranchDurableTaskRequest = exports.TriggerWorkflowRunResponse = exports.TriggerWorkflowRunRequest_DesiredWorkerLabelsEntry = exports.TriggerWorkflowRunRequest = exports.ReplayTasksResponse = exports.CancelTasksResponse = exports.TasksFilter = exports.ReplayTasksRequest = exports.CancelTasksRequest = exports.IdempotencyMethod = exports.ConcurrencyLimitStrategy = exports.RunStatus = exports.RateLimitDuration = exports.StickyStrategy = exports.protobufPackage = void 0;
|
|
9
9
|
exports.stickyStrategyFromJSON = stickyStrategyFromJSON;
|
|
10
10
|
exports.stickyStrategyToJSON = stickyStrategyToJSON;
|
|
11
11
|
exports.rateLimitDurationFromJSON = rateLimitDurationFromJSON;
|
|
@@ -14,6 +14,8 @@ exports.runStatusFromJSON = runStatusFromJSON;
|
|
|
14
14
|
exports.runStatusToJSON = runStatusToJSON;
|
|
15
15
|
exports.concurrencyLimitStrategyFromJSON = concurrencyLimitStrategyFromJSON;
|
|
16
16
|
exports.concurrencyLimitStrategyToJSON = concurrencyLimitStrategyToJSON;
|
|
17
|
+
exports.idempotencyMethodFromJSON = idempotencyMethodFromJSON;
|
|
18
|
+
exports.idempotencyMethodToJSON = idempotencyMethodToJSON;
|
|
17
19
|
/* eslint-disable */
|
|
18
20
|
const wire_1 = require("@bufbuild/protobuf/wire");
|
|
19
21
|
const timestamp_1 = require("../google/protobuf/timestamp");
|
|
@@ -218,6 +220,37 @@ function concurrencyLimitStrategyToJSON(object) {
|
|
|
218
220
|
return 'UNRECOGNIZED';
|
|
219
221
|
}
|
|
220
222
|
}
|
|
223
|
+
var IdempotencyMethod;
|
|
224
|
+
(function (IdempotencyMethod) {
|
|
225
|
+
IdempotencyMethod[IdempotencyMethod["TTL"] = 0] = "TTL";
|
|
226
|
+
IdempotencyMethod[IdempotencyMethod["STATUS"] = 1] = "STATUS";
|
|
227
|
+
IdempotencyMethod[IdempotencyMethod["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
|
|
228
|
+
})(IdempotencyMethod || (exports.IdempotencyMethod = IdempotencyMethod = {}));
|
|
229
|
+
function idempotencyMethodFromJSON(object) {
|
|
230
|
+
switch (object) {
|
|
231
|
+
case 0:
|
|
232
|
+
case 'TTL':
|
|
233
|
+
return IdempotencyMethod.TTL;
|
|
234
|
+
case 1:
|
|
235
|
+
case 'STATUS':
|
|
236
|
+
return IdempotencyMethod.STATUS;
|
|
237
|
+
case -1:
|
|
238
|
+
case 'UNRECOGNIZED':
|
|
239
|
+
default:
|
|
240
|
+
return IdempotencyMethod.UNRECOGNIZED;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function idempotencyMethodToJSON(object) {
|
|
244
|
+
switch (object) {
|
|
245
|
+
case IdempotencyMethod.TTL:
|
|
246
|
+
return 'TTL';
|
|
247
|
+
case IdempotencyMethod.STATUS:
|
|
248
|
+
return 'STATUS';
|
|
249
|
+
case IdempotencyMethod.UNRECOGNIZED:
|
|
250
|
+
default:
|
|
251
|
+
return 'UNRECOGNIZED';
|
|
252
|
+
}
|
|
253
|
+
}
|
|
221
254
|
function createBaseCancelTasksRequest() {
|
|
222
255
|
return { externalIds: [], filter: undefined };
|
|
223
256
|
}
|
|
@@ -1422,7 +1455,7 @@ exports.CreateWorkflowVersionRequest = {
|
|
|
1422
1455
|
},
|
|
1423
1456
|
};
|
|
1424
1457
|
function createBaseIdempotencyConfig() {
|
|
1425
|
-
return { expression: '', ttlMs: 0 };
|
|
1458
|
+
return { expression: '', ttlMs: 0, method: undefined };
|
|
1426
1459
|
}
|
|
1427
1460
|
exports.IdempotencyConfig = {
|
|
1428
1461
|
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
@@ -1432,6 +1465,9 @@ exports.IdempotencyConfig = {
|
|
|
1432
1465
|
if (message.ttlMs !== 0) {
|
|
1433
1466
|
writer.uint32(16).int64(message.ttlMs);
|
|
1434
1467
|
}
|
|
1468
|
+
if (message.method !== undefined) {
|
|
1469
|
+
writer.uint32(24).int32(message.method);
|
|
1470
|
+
}
|
|
1435
1471
|
return writer;
|
|
1436
1472
|
},
|
|
1437
1473
|
decode(input, length) {
|
|
@@ -1455,6 +1491,13 @@ exports.IdempotencyConfig = {
|
|
|
1455
1491
|
message.ttlMs = longToNumber(reader.int64());
|
|
1456
1492
|
continue;
|
|
1457
1493
|
}
|
|
1494
|
+
case 3: {
|
|
1495
|
+
if (tag !== 24) {
|
|
1496
|
+
break;
|
|
1497
|
+
}
|
|
1498
|
+
message.method = reader.int32();
|
|
1499
|
+
continue;
|
|
1500
|
+
}
|
|
1458
1501
|
}
|
|
1459
1502
|
if ((tag & 7) === 4 || tag === 0) {
|
|
1460
1503
|
break;
|
|
@@ -1471,6 +1514,7 @@ exports.IdempotencyConfig = {
|
|
|
1471
1514
|
: isSet(object.ttl_ms)
|
|
1472
1515
|
? globalThis.Number(object.ttl_ms)
|
|
1473
1516
|
: 0,
|
|
1517
|
+
method: isSet(object.method) ? idempotencyMethodFromJSON(object.method) : undefined,
|
|
1474
1518
|
};
|
|
1475
1519
|
},
|
|
1476
1520
|
toJSON(message) {
|
|
@@ -1481,16 +1525,20 @@ exports.IdempotencyConfig = {
|
|
|
1481
1525
|
if (message.ttlMs !== 0) {
|
|
1482
1526
|
obj.ttlMs = Math.round(message.ttlMs);
|
|
1483
1527
|
}
|
|
1528
|
+
if (message.method !== undefined) {
|
|
1529
|
+
obj.method = idempotencyMethodToJSON(message.method);
|
|
1530
|
+
}
|
|
1484
1531
|
return obj;
|
|
1485
1532
|
},
|
|
1486
1533
|
create(base) {
|
|
1487
1534
|
return exports.IdempotencyConfig.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
1488
1535
|
},
|
|
1489
1536
|
fromPartial(object) {
|
|
1490
|
-
var _a, _b;
|
|
1537
|
+
var _a, _b, _c;
|
|
1491
1538
|
const message = createBaseIdempotencyConfig();
|
|
1492
1539
|
message.expression = (_a = object.expression) !== null && _a !== void 0 ? _a : '';
|
|
1493
1540
|
message.ttlMs = (_b = object.ttlMs) !== null && _b !== void 0 ? _b : 0;
|
|
1541
|
+
message.method = (_c = object.method) !== null && _c !== void 0 ? _c : undefined;
|
|
1494
1542
|
return message;
|
|
1495
1543
|
},
|
|
1496
1544
|
};
|
|
@@ -6,6 +6,7 @@ interface LoadClientConfigOptions {
|
|
|
6
6
|
export declare class ConfigLoader {
|
|
7
7
|
static loadClientConfig(override?: Partial<ClientConfig>, config?: LoadClientConfigOptions): Partial<ClientConfig>;
|
|
8
8
|
private static parseIntEnv;
|
|
9
|
+
private static parseFloatEnv;
|
|
9
10
|
private static parseJsonArray;
|
|
10
11
|
static get default_yaml_config_path(): string;
|
|
11
12
|
static createCredentials(config: ClientConfig['tls_config']): ChannelCredentials;
|
|
@@ -44,7 +44,7 @@ const token_1 = require("./token");
|
|
|
44
44
|
const DEFAULT_CONFIG_FILE = '.hatchet.yaml';
|
|
45
45
|
class ConfigLoader {
|
|
46
46
|
static loadClientConfig(override, config) {
|
|
47
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
|
|
47
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30;
|
|
48
48
|
const yaml = this.loadYamlConfig(config === null || config === void 0 ? void 0 : config.path);
|
|
49
49
|
const tlsConfig = (_a = override === null || override === void 0 ? void 0 : override.tls_config) !== null && _a !== void 0 ? _a : {
|
|
50
50
|
tls_strategy: (_d = (_c = (_b = yaml === null || yaml === void 0 ? void 0 : yaml.tls_config) === null || _b === void 0 ? void 0 : _b.tls_strategy) !== null && _c !== void 0 ? _c : this.env('HATCHET_CLIENT_TLS_STRATEGY')) !== null && _d !== void 0 ? _d : 'tls',
|
|
@@ -74,7 +74,7 @@ class ConfigLoader {
|
|
|
74
74
|
apiUrl =
|
|
75
75
|
(_x = (_w = (_v = override === null || override === void 0 ? void 0 : override.api_url) !== null && _v !== void 0 ? _v : yaml === null || yaml === void 0 ? void 0 : yaml.api_url) !== null && _w !== void 0 ? _w : this.env('HATCHET_CLIENT_API_URL')) !== null && _x !== void 0 ? _x : addresses.serverUrl;
|
|
76
76
|
}
|
|
77
|
-
catch (
|
|
77
|
+
catch (_31) {
|
|
78
78
|
grpcBroadcastAddress =
|
|
79
79
|
(_z = (_y = override === null || override === void 0 ? void 0 : override.host_port) !== null && _y !== void 0 ? _y : yaml === null || yaml === void 0 ? void 0 : yaml.host_port) !== null && _z !== void 0 ? _z : this.env('HATCHET_CLIENT_HOST_PORT');
|
|
80
80
|
apiUrl = (_1 = (_0 = override === null || override === void 0 ? void 0 : override.api_url) !== null && _0 !== void 0 ? _0 : yaml === null || yaml === void 0 ? void 0 : yaml.api_url) !== null && _1 !== void 0 ? _1 : this.env('HATCHET_CLIENT_API_URL');
|
|
@@ -90,21 +90,13 @@ class ConfigLoader {
|
|
|
90
90
|
};
|
|
91
91
|
const grpcMaxRecvMessageLength = (_8 = (_7 = (_6 = override === null || override === void 0 ? void 0 : override.grpc_max_recv_message_length) !== null && _6 !== void 0 ? _6 : yaml === null || yaml === void 0 ? void 0 : yaml.grpc_max_recv_message_length) !== null && _7 !== void 0 ? _7 : this.parseIntEnv('HATCHET_CLIENT_GRPC_MAX_RECV_MESSAGE_LENGTH')) !== null && _8 !== void 0 ? _8 : 4 * 1024 * 1024;
|
|
92
92
|
const grpcMaxSendMessageLength = (_11 = (_10 = (_9 = override === null || override === void 0 ? void 0 : override.grpc_max_send_message_length) !== null && _9 !== void 0 ? _9 : yaml === null || yaml === void 0 ? void 0 : yaml.grpc_max_send_message_length) !== null && _10 !== void 0 ? _10 : this.parseIntEnv('HATCHET_CLIENT_GRPC_MAX_SEND_MESSAGE_LENGTH')) !== null && _11 !== void 0 ? _11 : 4 * 1024 * 1024;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
tls_config: tlsConfig,
|
|
98
|
-
healthcheck: healthCheckConfig,
|
|
99
|
-
log_level: (_16 = (_15 = (_14 = override === null || override === void 0 ? void 0 : override.log_level) !== null && _14 !== void 0 ? _14 : yaml === null || yaml === void 0 ? void 0 : yaml.log_level) !== null && _15 !== void 0 ? _15 : this.env('HATCHET_CLIENT_LOG_LEVEL')) !== null && _16 !== void 0 ? _16 : 'INFO',
|
|
100
|
-
tenant_id: tenantId,
|
|
101
|
-
namespace: namespace ? `${namespace}`.toLowerCase() : '',
|
|
102
|
-
otel: otelConfig,
|
|
103
|
-
grpc_max_recv_message_length: grpcMaxRecvMessageLength,
|
|
104
|
-
grpc_max_send_message_length: grpcMaxSendMessageLength,
|
|
105
|
-
cancellation_grace_period: (_17 = override === null || override === void 0 ? void 0 : override.cancellation_grace_period) !== null && _17 !== void 0 ? _17 : yaml === null || yaml === void 0 ? void 0 : yaml.cancellation_grace_period,
|
|
106
|
-
cancellation_warning_threshold: (_18 = override === null || override === void 0 ? void 0 : override.cancellation_warning_threshold) !== null && _18 !== void 0 ? _18 : yaml === null || yaml === void 0 ? void 0 : yaml.cancellation_warning_threshold,
|
|
93
|
+
const retrierConfig = {
|
|
94
|
+
maxAttempts: (_15 = (_13 = (_12 = override === null || override === void 0 ? void 0 : override.retrier) === null || _12 === void 0 ? void 0 : _12.maxAttempts) !== null && _13 !== void 0 ? _13 : (_14 = yaml === null || yaml === void 0 ? void 0 : yaml.retrier) === null || _14 === void 0 ? void 0 : _14.maxAttempts) !== null && _15 !== void 0 ? _15 : this.parseIntEnv('HATCHET_CLIENT_RETRIER_MAX_ATTEMPTS'),
|
|
95
|
+
initialInterval: (_19 = (_17 = (_16 = override === null || override === void 0 ? void 0 : override.retrier) === null || _16 === void 0 ? void 0 : _16.initialInterval) !== null && _17 !== void 0 ? _17 : (_18 = yaml === null || yaml === void 0 ? void 0 : yaml.retrier) === null || _18 === void 0 ? void 0 : _18.initialInterval) !== null && _19 !== void 0 ? _19 : this.parseFloatEnv('HATCHET_CLIENT_RETRIER_INITIAL_INTERVAL'),
|
|
96
|
+
maxJitter: (_23 = (_21 = (_20 = override === null || override === void 0 ? void 0 : override.retrier) === null || _20 === void 0 ? void 0 : _20.maxJitter) !== null && _21 !== void 0 ? _21 : (_22 = yaml === null || yaml === void 0 ? void 0 : yaml.retrier) === null || _22 === void 0 ? void 0 : _22.maxJitter) !== null && _23 !== void 0 ? _23 : this.parseIntEnv('HATCHET_CLIENT_RETRIER_MAX_JITTER'),
|
|
107
97
|
};
|
|
98
|
+
const hasRetrier = Object.values(retrierConfig).some((v) => v !== undefined);
|
|
99
|
+
return Object.assign({ token: (_25 = (_24 = override === null || override === void 0 ? void 0 : override.token) !== null && _24 !== void 0 ? _24 : yaml === null || yaml === void 0 ? void 0 : yaml.token) !== null && _25 !== void 0 ? _25 : this.env('HATCHET_CLIENT_TOKEN'), host_port: grpcBroadcastAddress, api_url: apiUrl, tls_config: tlsConfig, healthcheck: healthCheckConfig, log_level: (_28 = (_27 = (_26 = override === null || override === void 0 ? void 0 : override.log_level) !== null && _26 !== void 0 ? _26 : yaml === null || yaml === void 0 ? void 0 : yaml.log_level) !== null && _27 !== void 0 ? _27 : this.env('HATCHET_CLIENT_LOG_LEVEL')) !== null && _28 !== void 0 ? _28 : 'INFO', tenant_id: tenantId, namespace: namespace ? `${namespace}`.toLowerCase() : '', otel: otelConfig, grpc_max_recv_message_length: grpcMaxRecvMessageLength, grpc_max_send_message_length: grpcMaxSendMessageLength, cancellation_grace_period: (_29 = override === null || override === void 0 ? void 0 : override.cancellation_grace_period) !== null && _29 !== void 0 ? _29 : yaml === null || yaml === void 0 ? void 0 : yaml.cancellation_grace_period, cancellation_warning_threshold: (_30 = override === null || override === void 0 ? void 0 : override.cancellation_warning_threshold) !== null && _30 !== void 0 ? _30 : yaml === null || yaml === void 0 ? void 0 : yaml.cancellation_warning_threshold }, (hasRetrier ? { retrier: retrierConfig } : {}));
|
|
108
100
|
}
|
|
109
101
|
static parseIntEnv(envName) {
|
|
110
102
|
const value = this.env(envName);
|
|
@@ -115,6 +107,16 @@ class ConfigLoader {
|
|
|
115
107
|
}
|
|
116
108
|
return parseInt(value, 10);
|
|
117
109
|
}
|
|
110
|
+
static parseFloatEnv(envName) {
|
|
111
|
+
const value = this.env(envName);
|
|
112
|
+
if (value === undefined || value === '')
|
|
113
|
+
return undefined;
|
|
114
|
+
const parsed = parseFloat(value.trim());
|
|
115
|
+
if (isNaN(parsed) || parsed <= 0) {
|
|
116
|
+
throw new Error(`Invalid value for ${envName}: "${value}". Expected a positive number.`);
|
|
117
|
+
}
|
|
118
|
+
return parsed;
|
|
119
|
+
}
|
|
118
120
|
static parseJsonArray(value) {
|
|
119
121
|
try {
|
|
120
122
|
const parsed = JSON.parse(value);
|
package/util/retrier.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
import { Logger } from './logger';
|
|
2
|
-
export declare
|
|
2
|
+
export declare const DEFAULT_RETRY_INTERVAL = 0.1;
|
|
3
|
+
export declare const DEFAULT_RETRY_COUNT = 8;
|
|
4
|
+
export declare const DEFAULT_MAX_JITTER = 100;
|
|
5
|
+
export interface RetrierConfig {
|
|
6
|
+
maxAttempts?: number;
|
|
7
|
+
initialInterval?: number;
|
|
8
|
+
maxJitter?: number;
|
|
9
|
+
shouldRetry?: (e: unknown) => boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function retrier<T>(fn: () => Promise<T>, logger: Logger, config?: RetrierConfig): Promise<T>;
|
package/util/retrier.js
CHANGED
|
@@ -12,13 +12,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.DEFAULT_MAX_JITTER = exports.DEFAULT_RETRY_COUNT = exports.DEFAULT_RETRY_INTERVAL = void 0;
|
|
15
16
|
exports.retrier = retrier;
|
|
16
17
|
const sleep_1 = __importDefault(require("./sleep"));
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
function retrier(
|
|
21
|
-
return __awaiter(this,
|
|
18
|
+
exports.DEFAULT_RETRY_INTERVAL = 0.1; // seconds
|
|
19
|
+
exports.DEFAULT_RETRY_COUNT = 8;
|
|
20
|
+
exports.DEFAULT_MAX_JITTER = 100; // milliseconds
|
|
21
|
+
function retrier(fn, logger, config) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
var _a, _b, _c, _d;
|
|
24
|
+
const retries = Math.max(1, (_a = config === null || config === void 0 ? void 0 : config.maxAttempts) !== null && _a !== void 0 ? _a : exports.DEFAULT_RETRY_COUNT);
|
|
25
|
+
const interval = (_b = config === null || config === void 0 ? void 0 : config.initialInterval) !== null && _b !== void 0 ? _b : exports.DEFAULT_RETRY_INTERVAL;
|
|
26
|
+
const maxJitter = (_c = config === null || config === void 0 ? void 0 : config.maxJitter) !== null && _c !== void 0 ? _c : exports.DEFAULT_MAX_JITTER;
|
|
27
|
+
const shouldRetry = (_d = config === null || config === void 0 ? void 0 : config.shouldRetry) !== null && _d !== void 0 ? _d : (() => true);
|
|
22
28
|
let lastError;
|
|
23
29
|
for (let i = 0; i < retries; i++) {
|
|
24
30
|
try {
|
|
@@ -30,11 +36,11 @@ function retrier(fn_1, logger_1) {
|
|
|
30
36
|
}
|
|
31
37
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
32
38
|
logger.error(`Error: ${lastError.message}`);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
if (i < retries - 1) {
|
|
40
|
+
const exponentialDelay = interval * 2 ** i * 1000;
|
|
41
|
+
const jitter = Math.random() * maxJitter;
|
|
42
|
+
yield (0, sleep_1.default)(exponentialDelay + jitter);
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
throw lastError;
|
package/v1/client/admin.js
CHANGED
|
@@ -184,7 +184,7 @@ class AdminClient {
|
|
|
184
184
|
trailerMetadata = trailer;
|
|
185
185
|
},
|
|
186
186
|
});
|
|
187
|
-
}), this.logger,
|
|
187
|
+
}), this.logger, Object.assign(Object.assign({}, this.config.retrier), { shouldRetry: (e) => !isNiceGrpcAlreadyExists(e) }));
|
|
188
188
|
const id = resp.workflowRunId;
|
|
189
189
|
const ref = new workflow_run_ref_1.default(id, this.listenerClient, this.runs, options === null || options === void 0 ? void 0 : options.parentId, options === null || options === void 0 ? void 0 : options._standaloneTaskName);
|
|
190
190
|
yield ref.getWorkflowRunId();
|
|
@@ -242,8 +242,8 @@ class AdminClient {
|
|
|
242
242
|
bulkTrailerMetadata = trailer;
|
|
243
243
|
},
|
|
244
244
|
});
|
|
245
|
-
}), this.logger,
|
|
246
|
-
|
|
245
|
+
}), this.logger, Object.assign(Object.assign({}, this.config.retrier), { shouldRetry: (e) => !isNiceGrpcAlreadyExists(e) &&
|
|
246
|
+
!(isGrpcServiceError(e) && e.code === grpc_js_1.status.ALREADY_EXISTS) }));
|
|
247
247
|
this.logger.debug(`batch ${batchIndex + 1} of ${batches.length}`);
|
|
248
248
|
// Map the results back to their original indices
|
|
249
249
|
const batchResults = bulkTriggerWorkflowResponse.workflowRunIds.map((resp, index) => {
|
|
@@ -277,7 +277,7 @@ class AdminClient {
|
|
|
277
277
|
limit,
|
|
278
278
|
duration,
|
|
279
279
|
};
|
|
280
|
-
yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () { return this.workflowsGrpc.putRateLimit(request); }), this.logger);
|
|
280
|
+
yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () { return this.workflowsGrpc.putRateLimit(request); }), this.logger, this.config.retrier);
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
283
|
}
|
|
@@ -63,6 +63,7 @@ const dispatcher_1 = require("../../../protoc/dispatcher");
|
|
|
63
63
|
const hatchet_promise_1 = __importStar(require("../../../util/hatchet-promise/hatchet-promise"));
|
|
64
64
|
const workflows_1 = require("../../../protoc/workflows");
|
|
65
65
|
const logger_1 = require("../../../util/logger");
|
|
66
|
+
const workflows_2 = require("../../../protoc/v1/workflows");
|
|
66
67
|
const task_1 = require("../../task");
|
|
67
68
|
const transformer_1 = require("../../conditions/transformer");
|
|
68
69
|
const z = __importStar(require("zod/v4"));
|
|
@@ -338,7 +339,12 @@ class InternalWorker {
|
|
|
338
339
|
idempotency: workflow.idempotency
|
|
339
340
|
? {
|
|
340
341
|
expression: workflow.idempotency.expression,
|
|
341
|
-
ttlMs: workflow.idempotency.
|
|
342
|
+
ttlMs: workflow.idempotency.strategy === 'status'
|
|
343
|
+
? workflow.idempotency.fallbackTtlMs
|
|
344
|
+
: workflow.idempotency.ttlMs,
|
|
345
|
+
method: workflow.idempotency.strategy === 'status'
|
|
346
|
+
? workflows_2.IdempotencyMethod.STATUS
|
|
347
|
+
: workflows_2.IdempotencyMethod.TTL,
|
|
342
348
|
}
|
|
343
349
|
: undefined,
|
|
344
350
|
});
|
|
@@ -8,3 +8,6 @@ export declare const idempotentTask: import("../..").TaskWorkflowDeclaration<Ide
|
|
|
8
8
|
export declare const idempotentTaskShortWindow: import("../..").TaskWorkflowDeclaration<IdempotencyInput, {
|
|
9
9
|
result: string;
|
|
10
10
|
}, {}, {}, {}, {}>;
|
|
11
|
+
export declare const idempotentStatusBasedTask: import("../..").TaskWorkflowDeclaration<IdempotencyInput, {
|
|
12
|
+
result: string;
|
|
13
|
+
}, {}, {}, {}, {}>;
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.idempotentTaskShortWindow = exports.idempotentTask = exports.EVENT_KEY = void 0;
|
|
12
|
+
exports.idempotentStatusBasedTask = exports.idempotentTaskShortWindow = exports.idempotentTask = exports.EVENT_KEY = void 0;
|
|
13
13
|
const hatchet_client_1 = require("../hatchet-client");
|
|
14
14
|
exports.EVENT_KEY = 'ts-e2e:idempotency-example';
|
|
15
15
|
// > idempotency
|
|
@@ -37,3 +37,16 @@ exports.idempotentTaskShortWindow = hatchet_client_1.hatchet.task({
|
|
|
37
37
|
return { result: `Hello, world from task ${input.id}` };
|
|
38
38
|
}),
|
|
39
39
|
});
|
|
40
|
+
// > status-based-idempotency
|
|
41
|
+
exports.idempotentStatusBasedTask = hatchet_client_1.hatchet.task({
|
|
42
|
+
name: 'ts-e2e-idempotent-status-based-task',
|
|
43
|
+
idempotency: {
|
|
44
|
+
strategy: 'status',
|
|
45
|
+
expression: 'input.id',
|
|
46
|
+
fallbackTtlMs: 10000,
|
|
47
|
+
},
|
|
48
|
+
fn: (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
return { result: `Hello, world from task ${input.id}` };
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
// !!
|
package/v1/task.d.ts
CHANGED
|
@@ -56,10 +56,22 @@ export type TTLBasedIdempotencyConfig = BaseIdempotencyConfig & {
|
|
|
56
56
|
*/
|
|
57
57
|
ttlMs: number;
|
|
58
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Status-based idempotency: keeps the idempotency key alive until the associated run
|
|
61
|
+
* reaches a terminal status. `fallbackTtlMs` caps how long the key can live before it's evicted.
|
|
62
|
+
*/
|
|
63
|
+
export type StatusBasedIdempotencyConfig = BaseIdempotencyConfig & {
|
|
64
|
+
strategy: 'status';
|
|
65
|
+
/**
|
|
66
|
+
* Fallback time-to-live (in milliseconds): the longest the idempotency key can live
|
|
67
|
+
* before it's evicted, even if the run has not reached a terminal status.
|
|
68
|
+
*/
|
|
69
|
+
fallbackTtlMs: number;
|
|
70
|
+
};
|
|
59
71
|
/**
|
|
60
72
|
* Union of all supported idempotency configurations.
|
|
61
73
|
*/
|
|
62
|
-
export type IdempotencyConfig = TTLBasedIdempotencyConfig;
|
|
74
|
+
export type IdempotencyConfig = TTLBasedIdempotencyConfig | StatusBasedIdempotencyConfig;
|
|
63
75
|
export declare class NonRetryableError extends Error {
|
|
64
76
|
constructor(message?: string);
|
|
65
77
|
}
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const HATCHET_VERSION = "1.
|
|
1
|
+
export declare const HATCHET_VERSION = "1.27.0";
|
package/version.js
CHANGED