@hatchet-dev/typescript-sdk 1.25.0 → 1.26.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.
- package/clients/dispatcher/action-listener.d.ts +1 -0
- package/clients/dispatcher/action-listener.js +5 -0
- package/clients/rest/generated/Api.d.ts +77 -3
- package/clients/rest/generated/Api.js +42 -2
- package/clients/rest/generated/data-contracts.d.ts +126 -2
- package/clients/rest/generated/data-contracts.js +26 -1
- package/opentelemetry/instrumentor.js +2 -1
- package/package.json +3 -3
- package/protoc/google/protobuf/any.d.ts +133 -0
- package/protoc/google/protobuf/any.js +112 -0
- package/protoc/google/rpc/status.d.ts +45 -0
- package/protoc/google/rpc/status.js +102 -0
- package/protoc/v1/workflows.d.ts +21 -0
- package/protoc/v1/workflows.js +231 -1
- package/util/errors/bulk-trigger-idempotency-collision-error.d.ts +6 -0
- package/util/errors/bulk-trigger-idempotency-collision-error.js +13 -0
- package/util/errors/idempotency-collision-error.d.ts +5 -0
- package/util/errors/idempotency-collision-error.js +16 -0
- package/util/retrier.d.ts +1 -1
- package/util/retrier.js +4 -1
- package/v1/client/admin.js +125 -9
- package/v1/client/worker/context.d.ts +8 -1
- package/v1/client/worker/context.js +11 -1
- package/v1/client/worker/worker-internal.js +6 -0
- package/v1/declaration.d.ts +6 -1
- package/v1/examples/e2e-worker.js +30 -27
- package/v1/examples/idempotency/run.d.ts +1 -0
- package/v1/examples/idempotency/run.js +37 -0
- package/v1/examples/idempotency/workflow.d.ts +10 -0
- package/v1/examples/idempotency/workflow.js +39 -0
- package/v1/index.d.ts +2 -0
- package/v1/index.js +5 -1
- package/v1/task.d.ts +24 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
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.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.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;
|
|
@@ -1111,6 +1111,7 @@ function createBaseCreateWorkflowVersionRequest() {
|
|
|
1111
1111
|
concurrencyArr: [],
|
|
1112
1112
|
defaultFilters: [],
|
|
1113
1113
|
inputJsonSchema: undefined,
|
|
1114
|
+
idempotency: undefined,
|
|
1114
1115
|
};
|
|
1115
1116
|
}
|
|
1116
1117
|
exports.CreateWorkflowVersionRequest = {
|
|
@@ -1157,6 +1158,9 @@ exports.CreateWorkflowVersionRequest = {
|
|
|
1157
1158
|
if (message.inputJsonSchema !== undefined) {
|
|
1158
1159
|
writer.uint32(114).bytes(message.inputJsonSchema);
|
|
1159
1160
|
}
|
|
1161
|
+
if (message.idempotency !== undefined) {
|
|
1162
|
+
exports.IdempotencyConfig.encode(message.idempotency, writer.uint32(122).fork()).join();
|
|
1163
|
+
}
|
|
1160
1164
|
return writer;
|
|
1161
1165
|
},
|
|
1162
1166
|
decode(input, length) {
|
|
@@ -1264,6 +1268,13 @@ exports.CreateWorkflowVersionRequest = {
|
|
|
1264
1268
|
message.inputJsonSchema = reader.bytes();
|
|
1265
1269
|
continue;
|
|
1266
1270
|
}
|
|
1271
|
+
case 15: {
|
|
1272
|
+
if (tag !== 122) {
|
|
1273
|
+
break;
|
|
1274
|
+
}
|
|
1275
|
+
message.idempotency = exports.IdempotencyConfig.decode(reader, reader.uint32());
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1267
1278
|
}
|
|
1268
1279
|
if ((tag & 7) === 4 || tag === 0) {
|
|
1269
1280
|
break;
|
|
@@ -1322,6 +1333,9 @@ exports.CreateWorkflowVersionRequest = {
|
|
|
1322
1333
|
: isSet(object.input_json_schema)
|
|
1323
1334
|
? bytesFromBase64(object.input_json_schema)
|
|
1324
1335
|
: undefined,
|
|
1336
|
+
idempotency: isSet(object.idempotency)
|
|
1337
|
+
? exports.IdempotencyConfig.fromJSON(object.idempotency)
|
|
1338
|
+
: undefined,
|
|
1325
1339
|
};
|
|
1326
1340
|
},
|
|
1327
1341
|
toJSON(message) {
|
|
@@ -1369,6 +1383,9 @@ exports.CreateWorkflowVersionRequest = {
|
|
|
1369
1383
|
if (message.inputJsonSchema !== undefined) {
|
|
1370
1384
|
obj.inputJsonSchema = base64FromBytes(message.inputJsonSchema);
|
|
1371
1385
|
}
|
|
1386
|
+
if (message.idempotency !== undefined) {
|
|
1387
|
+
obj.idempotency = exports.IdempotencyConfig.toJSON(message.idempotency);
|
|
1388
|
+
}
|
|
1372
1389
|
return obj;
|
|
1373
1390
|
},
|
|
1374
1391
|
create(base) {
|
|
@@ -1397,6 +1414,219 @@ exports.CreateWorkflowVersionRequest = {
|
|
|
1397
1414
|
message.concurrencyArr = ((_k = object.concurrencyArr) === null || _k === void 0 ? void 0 : _k.map((e) => exports.Concurrency.fromPartial(e))) || [];
|
|
1398
1415
|
message.defaultFilters = ((_l = object.defaultFilters) === null || _l === void 0 ? void 0 : _l.map((e) => exports.DefaultFilter.fromPartial(e))) || [];
|
|
1399
1416
|
message.inputJsonSchema = (_m = object.inputJsonSchema) !== null && _m !== void 0 ? _m : undefined;
|
|
1417
|
+
message.idempotency =
|
|
1418
|
+
object.idempotency !== undefined && object.idempotency !== null
|
|
1419
|
+
? exports.IdempotencyConfig.fromPartial(object.idempotency)
|
|
1420
|
+
: undefined;
|
|
1421
|
+
return message;
|
|
1422
|
+
},
|
|
1423
|
+
};
|
|
1424
|
+
function createBaseIdempotencyConfig() {
|
|
1425
|
+
return { expression: '', ttlMs: 0 };
|
|
1426
|
+
}
|
|
1427
|
+
exports.IdempotencyConfig = {
|
|
1428
|
+
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
1429
|
+
if (message.expression !== '') {
|
|
1430
|
+
writer.uint32(10).string(message.expression);
|
|
1431
|
+
}
|
|
1432
|
+
if (message.ttlMs !== 0) {
|
|
1433
|
+
writer.uint32(16).int64(message.ttlMs);
|
|
1434
|
+
}
|
|
1435
|
+
return writer;
|
|
1436
|
+
},
|
|
1437
|
+
decode(input, length) {
|
|
1438
|
+
const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
|
|
1439
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
1440
|
+
const message = createBaseIdempotencyConfig();
|
|
1441
|
+
while (reader.pos < end) {
|
|
1442
|
+
const tag = reader.uint32();
|
|
1443
|
+
switch (tag >>> 3) {
|
|
1444
|
+
case 1: {
|
|
1445
|
+
if (tag !== 10) {
|
|
1446
|
+
break;
|
|
1447
|
+
}
|
|
1448
|
+
message.expression = reader.string();
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
case 2: {
|
|
1452
|
+
if (tag !== 16) {
|
|
1453
|
+
break;
|
|
1454
|
+
}
|
|
1455
|
+
message.ttlMs = longToNumber(reader.int64());
|
|
1456
|
+
continue;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
reader.skip(tag & 7);
|
|
1463
|
+
}
|
|
1464
|
+
return message;
|
|
1465
|
+
},
|
|
1466
|
+
fromJSON(object) {
|
|
1467
|
+
return {
|
|
1468
|
+
expression: isSet(object.expression) ? globalThis.String(object.expression) : '',
|
|
1469
|
+
ttlMs: isSet(object.ttlMs)
|
|
1470
|
+
? globalThis.Number(object.ttlMs)
|
|
1471
|
+
: isSet(object.ttl_ms)
|
|
1472
|
+
? globalThis.Number(object.ttl_ms)
|
|
1473
|
+
: 0,
|
|
1474
|
+
};
|
|
1475
|
+
},
|
|
1476
|
+
toJSON(message) {
|
|
1477
|
+
const obj = {};
|
|
1478
|
+
if (message.expression !== '') {
|
|
1479
|
+
obj.expression = message.expression;
|
|
1480
|
+
}
|
|
1481
|
+
if (message.ttlMs !== 0) {
|
|
1482
|
+
obj.ttlMs = Math.round(message.ttlMs);
|
|
1483
|
+
}
|
|
1484
|
+
return obj;
|
|
1485
|
+
},
|
|
1486
|
+
create(base) {
|
|
1487
|
+
return exports.IdempotencyConfig.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
1488
|
+
},
|
|
1489
|
+
fromPartial(object) {
|
|
1490
|
+
var _a, _b;
|
|
1491
|
+
const message = createBaseIdempotencyConfig();
|
|
1492
|
+
message.expression = (_a = object.expression) !== null && _a !== void 0 ? _a : '';
|
|
1493
|
+
message.ttlMs = (_b = object.ttlMs) !== null && _b !== void 0 ? _b : 0;
|
|
1494
|
+
return message;
|
|
1495
|
+
},
|
|
1496
|
+
};
|
|
1497
|
+
function createBaseIdempotencyCollisionError() {
|
|
1498
|
+
return { existingRunExternalId: '' };
|
|
1499
|
+
}
|
|
1500
|
+
exports.IdempotencyCollisionError = {
|
|
1501
|
+
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
1502
|
+
if (message.existingRunExternalId !== '') {
|
|
1503
|
+
writer.uint32(10).string(message.existingRunExternalId);
|
|
1504
|
+
}
|
|
1505
|
+
return writer;
|
|
1506
|
+
},
|
|
1507
|
+
decode(input, length) {
|
|
1508
|
+
const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
|
|
1509
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
1510
|
+
const message = createBaseIdempotencyCollisionError();
|
|
1511
|
+
while (reader.pos < end) {
|
|
1512
|
+
const tag = reader.uint32();
|
|
1513
|
+
switch (tag >>> 3) {
|
|
1514
|
+
case 1: {
|
|
1515
|
+
if (tag !== 10) {
|
|
1516
|
+
break;
|
|
1517
|
+
}
|
|
1518
|
+
message.existingRunExternalId = reader.string();
|
|
1519
|
+
continue;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
1523
|
+
break;
|
|
1524
|
+
}
|
|
1525
|
+
reader.skip(tag & 7);
|
|
1526
|
+
}
|
|
1527
|
+
return message;
|
|
1528
|
+
},
|
|
1529
|
+
fromJSON(object) {
|
|
1530
|
+
return {
|
|
1531
|
+
existingRunExternalId: isSet(object.existingRunExternalId)
|
|
1532
|
+
? globalThis.String(object.existingRunExternalId)
|
|
1533
|
+
: isSet(object.existing_run_external_id)
|
|
1534
|
+
? globalThis.String(object.existing_run_external_id)
|
|
1535
|
+
: '',
|
|
1536
|
+
};
|
|
1537
|
+
},
|
|
1538
|
+
toJSON(message) {
|
|
1539
|
+
const obj = {};
|
|
1540
|
+
if (message.existingRunExternalId !== '') {
|
|
1541
|
+
obj.existingRunExternalId = message.existingRunExternalId;
|
|
1542
|
+
}
|
|
1543
|
+
return obj;
|
|
1544
|
+
},
|
|
1545
|
+
create(base) {
|
|
1546
|
+
return exports.IdempotencyCollisionError.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
1547
|
+
},
|
|
1548
|
+
fromPartial(object) {
|
|
1549
|
+
var _a;
|
|
1550
|
+
const message = createBaseIdempotencyCollisionError();
|
|
1551
|
+
message.existingRunExternalId = (_a = object.existingRunExternalId) !== null && _a !== void 0 ? _a : '';
|
|
1552
|
+
return message;
|
|
1553
|
+
},
|
|
1554
|
+
};
|
|
1555
|
+
function createBaseBulkTriggerIdempotencyCollisionError() {
|
|
1556
|
+
return { successfulWorkflowRunExternalIds: [], collisions: [] };
|
|
1557
|
+
}
|
|
1558
|
+
exports.BulkTriggerIdempotencyCollisionError = {
|
|
1559
|
+
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
1560
|
+
for (const v of message.successfulWorkflowRunExternalIds) {
|
|
1561
|
+
writer.uint32(10).string(v);
|
|
1562
|
+
}
|
|
1563
|
+
for (const v of message.collisions) {
|
|
1564
|
+
exports.IdempotencyCollisionError.encode(v, writer.uint32(18).fork()).join();
|
|
1565
|
+
}
|
|
1566
|
+
return writer;
|
|
1567
|
+
},
|
|
1568
|
+
decode(input, length) {
|
|
1569
|
+
const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
|
|
1570
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
1571
|
+
const message = createBaseBulkTriggerIdempotencyCollisionError();
|
|
1572
|
+
while (reader.pos < end) {
|
|
1573
|
+
const tag = reader.uint32();
|
|
1574
|
+
switch (tag >>> 3) {
|
|
1575
|
+
case 1: {
|
|
1576
|
+
if (tag !== 10) {
|
|
1577
|
+
break;
|
|
1578
|
+
}
|
|
1579
|
+
message.successfulWorkflowRunExternalIds.push(reader.string());
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
case 2: {
|
|
1583
|
+
if (tag !== 18) {
|
|
1584
|
+
break;
|
|
1585
|
+
}
|
|
1586
|
+
message.collisions.push(exports.IdempotencyCollisionError.decode(reader, reader.uint32()));
|
|
1587
|
+
continue;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
reader.skip(tag & 7);
|
|
1594
|
+
}
|
|
1595
|
+
return message;
|
|
1596
|
+
},
|
|
1597
|
+
fromJSON(object) {
|
|
1598
|
+
return {
|
|
1599
|
+
successfulWorkflowRunExternalIds: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.successfulWorkflowRunExternalIds)
|
|
1600
|
+
? object.successfulWorkflowRunExternalIds.map((e) => globalThis.String(e))
|
|
1601
|
+
: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.successful_workflow_run_external_ids)
|
|
1602
|
+
? object.successful_workflow_run_external_ids.map((e) => globalThis.String(e))
|
|
1603
|
+
: [],
|
|
1604
|
+
collisions: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.collisions)
|
|
1605
|
+
? object.collisions.map((e) => exports.IdempotencyCollisionError.fromJSON(e))
|
|
1606
|
+
: [],
|
|
1607
|
+
};
|
|
1608
|
+
},
|
|
1609
|
+
toJSON(message) {
|
|
1610
|
+
var _a, _b;
|
|
1611
|
+
const obj = {};
|
|
1612
|
+
if ((_a = message.successfulWorkflowRunExternalIds) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1613
|
+
obj.successfulWorkflowRunExternalIds = message.successfulWorkflowRunExternalIds;
|
|
1614
|
+
}
|
|
1615
|
+
if ((_b = message.collisions) === null || _b === void 0 ? void 0 : _b.length) {
|
|
1616
|
+
obj.collisions = message.collisions.map((e) => exports.IdempotencyCollisionError.toJSON(e));
|
|
1617
|
+
}
|
|
1618
|
+
return obj;
|
|
1619
|
+
},
|
|
1620
|
+
create(base) {
|
|
1621
|
+
return exports.BulkTriggerIdempotencyCollisionError.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
1622
|
+
},
|
|
1623
|
+
fromPartial(object) {
|
|
1624
|
+
var _a, _b, _c, _d;
|
|
1625
|
+
const message = createBaseBulkTriggerIdempotencyCollisionError();
|
|
1626
|
+
message.successfulWorkflowRunExternalIds =
|
|
1627
|
+
(_b = (_a = object.successfulWorkflowRunExternalIds) === null || _a === void 0 ? void 0 : _a.map((e) => e)) !== null && _b !== void 0 ? _b : [];
|
|
1628
|
+
message.collisions =
|
|
1629
|
+
(_d = (_c = object.collisions) === null || _c === void 0 ? void 0 : _c.map((e) => exports.IdempotencyCollisionError.fromPartial(e))) !== null && _d !== void 0 ? _d : [];
|
|
1400
1630
|
return message;
|
|
1401
1631
|
},
|
|
1402
1632
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IdempotencyCollisionError } from './idempotency-collision-error';
|
|
2
|
+
export declare class BulkTriggerIdempotencyCollisionError extends Error {
|
|
3
|
+
successfulWorkflowRunExternalIds: string[];
|
|
4
|
+
collisions: IdempotencyCollisionError[];
|
|
5
|
+
constructor(successfulWorkflowRunExternalIds: string[], collisions: IdempotencyCollisionError[]);
|
|
6
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BulkTriggerIdempotencyCollisionError = void 0;
|
|
4
|
+
class BulkTriggerIdempotencyCollisionError extends Error {
|
|
5
|
+
constructor(successfulWorkflowRunExternalIds, collisions) {
|
|
6
|
+
super('idempotency key collision in bulk trigger');
|
|
7
|
+
this.name = 'BulkTriggerIdempotencyCollisionError';
|
|
8
|
+
this.successfulWorkflowRunExternalIds = successfulWorkflowRunExternalIds;
|
|
9
|
+
this.collisions = collisions;
|
|
10
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.BulkTriggerIdempotencyCollisionError = BulkTriggerIdempotencyCollisionError;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.IdempotencyCollisionError = void 0;
|
|
7
|
+
const hatchet_error_1 = __importDefault(require("./hatchet-error"));
|
|
8
|
+
class IdempotencyCollisionError extends hatchet_error_1.default {
|
|
9
|
+
constructor(existingRunExternalId) {
|
|
10
|
+
super(`idempotency key collision: existing run ${existingRunExternalId} already exists`);
|
|
11
|
+
this.name = 'IdempotencyCollisionError';
|
|
12
|
+
this.existingRunExternalId = existingRunExternalId;
|
|
13
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.IdempotencyCollisionError = IdempotencyCollisionError;
|
package/util/retrier.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Logger } from './logger';
|
|
2
|
-
export declare function retrier<T>(fn: () => Promise<T>, logger: Logger, retries?: number, interval?: number): Promise<T>;
|
|
2
|
+
export declare function retrier<T>(fn: () => Promise<T>, logger: Logger, retries?: number, interval?: number, shouldRetry?: (e: unknown) => boolean): Promise<T>;
|
package/util/retrier.js
CHANGED
|
@@ -18,13 +18,16 @@ const DEFAULT_RETRY_INTERVAL = 0.1; // seconds
|
|
|
18
18
|
const DEFAULT_RETRY_COUNT = 8;
|
|
19
19
|
const MAX_JITTER = 100; // milliseconds
|
|
20
20
|
function retrier(fn_1, logger_1) {
|
|
21
|
-
return __awaiter(this, arguments, void 0, function* (fn, logger, retries = DEFAULT_RETRY_COUNT, interval = DEFAULT_RETRY_INTERVAL) {
|
|
21
|
+
return __awaiter(this, arguments, void 0, function* (fn, logger, retries = DEFAULT_RETRY_COUNT, interval = DEFAULT_RETRY_INTERVAL, shouldRetry = () => true) {
|
|
22
22
|
let lastError;
|
|
23
23
|
for (let i = 0; i < retries; i++) {
|
|
24
24
|
try {
|
|
25
25
|
return yield fn();
|
|
26
26
|
}
|
|
27
27
|
catch (e) {
|
|
28
|
+
if (!shouldRetry(e)) {
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
28
31
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
29
32
|
logger.error(`Error: ${lastError.message}`);
|
|
30
33
|
// Calculate exponential backoff with random jitter
|
package/v1/client/admin.js
CHANGED
|
@@ -25,14 +25,99 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.AdminClient = void 0;
|
|
27
27
|
const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
|
|
28
|
+
const idempotency_collision_error_1 = require("../../util/errors/idempotency-collision-error");
|
|
29
|
+
const bulk_trigger_idempotency_collision_error_1 = require("../../util/errors/bulk-trigger-idempotency-collision-error");
|
|
28
30
|
const workflow_run_ref_1 = __importDefault(require("../../util/workflow-run-ref"));
|
|
31
|
+
const grpc_js_1 = require("@grpc/grpc-js");
|
|
32
|
+
const status_1 = require("../../protoc/google/rpc/status");
|
|
33
|
+
const workflows_1 = require("../../protoc/v1/workflows");
|
|
34
|
+
const nice_grpc_common_1 = require("nice-grpc-common");
|
|
29
35
|
const grpc_helpers_1 = require("../../util/grpc-helpers");
|
|
30
36
|
const child_listener_client_1 = require("../../clients/listeners/run-listener/child-listener-client");
|
|
31
|
-
const
|
|
32
|
-
const
|
|
37
|
+
const workflows_2 = require("../../protoc/workflows");
|
|
38
|
+
const workflows_3 = require("../../protoc/v1/workflows");
|
|
33
39
|
const retrier_1 = require("../../util/retrier");
|
|
34
40
|
const batch_1 = require("../../util/batch");
|
|
35
41
|
const apply_namespace_1 = require("../../util/apply-namespace");
|
|
42
|
+
function isGrpcServiceError(e) {
|
|
43
|
+
return e instanceof Error && 'code' in e && 'metadata' in e;
|
|
44
|
+
}
|
|
45
|
+
function extractExistingRunIdFromGrpcError(e) {
|
|
46
|
+
var _a;
|
|
47
|
+
try {
|
|
48
|
+
const [binData] = e.metadata.get('grpc-status-details-bin');
|
|
49
|
+
if (!binData)
|
|
50
|
+
return '';
|
|
51
|
+
const status = status_1.Status.decode(binData instanceof Buffer ? binData : Buffer.from(binData));
|
|
52
|
+
for (const detail of status.details) {
|
|
53
|
+
if (detail.typeUrl.includes('IdempotencyCollisionError')) {
|
|
54
|
+
return (_a = workflows_1.IdempotencyCollisionError.decode(detail.value).existingRunExternalId) !== null && _a !== void 0 ? _a : '';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (_b) {
|
|
59
|
+
// ignore decoding errors
|
|
60
|
+
}
|
|
61
|
+
return '';
|
|
62
|
+
}
|
|
63
|
+
function isNiceGrpcAlreadyExists(e) {
|
|
64
|
+
return e instanceof nice_grpc_common_1.ClientError && e.code === nice_grpc_common_1.Status.ALREADY_EXISTS;
|
|
65
|
+
}
|
|
66
|
+
function decodeBulkTriggerCollision(status) {
|
|
67
|
+
for (const detail of status.details) {
|
|
68
|
+
if (detail.typeUrl.includes('BulkTriggerIdempotencyCollisionError')) {
|
|
69
|
+
const proto = workflows_1.BulkTriggerIdempotencyCollisionError.decode(detail.value);
|
|
70
|
+
return new bulk_trigger_idempotency_collision_error_1.BulkTriggerIdempotencyCollisionError(proto.successfulWorkflowRunExternalIds, proto.collisions.map((c) => new idempotency_collision_error_1.IdempotencyCollisionError(c.existingRunExternalId)));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function extractBulkTriggerCollisionFromGrpcError(e) {
|
|
76
|
+
try {
|
|
77
|
+
const [binData] = e.metadata.get('grpc-status-details-bin');
|
|
78
|
+
if (!binData)
|
|
79
|
+
return null;
|
|
80
|
+
const status = status_1.Status.decode(binData instanceof Buffer ? binData : Buffer.from(binData));
|
|
81
|
+
return decodeBulkTriggerCollision(status);
|
|
82
|
+
}
|
|
83
|
+
catch (_a) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function extractBulkTriggerCollisionFromNiceGrpcMetadata(metadata) {
|
|
88
|
+
if (!metadata)
|
|
89
|
+
return null;
|
|
90
|
+
try {
|
|
91
|
+
const binData = metadata.get('grpc-status-details-bin');
|
|
92
|
+
if (!binData)
|
|
93
|
+
return null;
|
|
94
|
+
const status = status_1.Status.decode(binData);
|
|
95
|
+
return decodeBulkTriggerCollision(status);
|
|
96
|
+
}
|
|
97
|
+
catch (_a) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function extractRunIdFromNiceGrpcMetadata(metadata) {
|
|
102
|
+
var _a;
|
|
103
|
+
if (!metadata)
|
|
104
|
+
return '';
|
|
105
|
+
try {
|
|
106
|
+
const binData = metadata.get('grpc-status-details-bin');
|
|
107
|
+
if (!binData)
|
|
108
|
+
return '';
|
|
109
|
+
const status = status_1.Status.decode(binData);
|
|
110
|
+
for (const detail of status.details) {
|
|
111
|
+
if (detail.typeUrl.includes('IdempotencyCollisionError')) {
|
|
112
|
+
return (_a = workflows_1.IdempotencyCollisionError.decode(detail.value).existingRunExternalId) !== null && _a !== void 0 ? _a : '';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (_b) {
|
|
117
|
+
// ignore decoding errors
|
|
118
|
+
}
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
36
121
|
function convertDesiredWorkerLabels(labels) {
|
|
37
122
|
return Object.fromEntries(Object.entries(labels).map(([key, label]) => [
|
|
38
123
|
key,
|
|
@@ -49,9 +134,9 @@ class AdminClient {
|
|
|
49
134
|
constructor(config, api, runs) {
|
|
50
135
|
this.config = config;
|
|
51
136
|
this.logger = config.logger(`Admin`, config.log_level);
|
|
52
|
-
const { client, channel, factory } = (0, grpc_helpers_1.createGrpcClient)(config,
|
|
137
|
+
const { client, channel, factory } = (0, grpc_helpers_1.createGrpcClient)(config, workflows_2.WorkflowServiceDefinition);
|
|
53
138
|
this.workflowsGrpc = client;
|
|
54
|
-
this.adminGrpc = factory.create(
|
|
139
|
+
this.adminGrpc = factory.create(workflows_3.AdminServiceDefinition, channel);
|
|
55
140
|
this.listenerClient = new child_listener_client_1.RunListenerClient(config, channel, factory, api);
|
|
56
141
|
this.runs = runs;
|
|
57
142
|
}
|
|
@@ -82,6 +167,7 @@ class AdminClient {
|
|
|
82
167
|
*/
|
|
83
168
|
runWorkflow(workflowName, input, options) {
|
|
84
169
|
return __awaiter(this, void 0, void 0, function* () {
|
|
170
|
+
let trailerMetadata;
|
|
85
171
|
try {
|
|
86
172
|
const computedName = (0, apply_namespace_1.applyNamespace)(workflowName, this.config.namespace).toLowerCase();
|
|
87
173
|
const inputStr = JSON.stringify(input);
|
|
@@ -92,14 +178,26 @@ class AdminClient {
|
|
|
92
178
|
parentTaskRunExternalId: parentTaskRunExternalId !== null && parentTaskRunExternalId !== void 0 ? parentTaskRunExternalId : parentStepRunId, additionalMetadata: additionalMetadata ? JSON.stringify(additionalMetadata) : undefined, priority: opts.priority, desiredWorkerLabels: desiredWorkerLabels
|
|
93
179
|
? convertDesiredWorkerLabels(desiredWorkerLabels)
|
|
94
180
|
: {} });
|
|
95
|
-
const resp = yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () {
|
|
181
|
+
const resp = yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
return this.workflowsGrpc.triggerWorkflow(request, {
|
|
183
|
+
onTrailer: (trailer) => {
|
|
184
|
+
trailerMetadata = trailer;
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}), this.logger, undefined, undefined, (e) => !isNiceGrpcAlreadyExists(e));
|
|
96
188
|
const id = resp.workflowRunId;
|
|
97
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);
|
|
98
190
|
yield ref.getWorkflowRunId();
|
|
99
191
|
return ref;
|
|
100
192
|
}
|
|
101
193
|
catch (e) {
|
|
102
|
-
|
|
194
|
+
if (isGrpcServiceError(e) && e.code === grpc_js_1.status.ALREADY_EXISTS) {
|
|
195
|
+
throw new idempotency_collision_error_1.IdempotencyCollisionError(extractExistingRunIdFromGrpcError(e));
|
|
196
|
+
}
|
|
197
|
+
if (isNiceGrpcAlreadyExists(e)) {
|
|
198
|
+
throw new idempotency_collision_error_1.IdempotencyCollisionError(extractRunIdFromNiceGrpcMetadata(trailerMetadata));
|
|
199
|
+
}
|
|
200
|
+
throw new hatchet_error_1.default(e instanceof Error ? e.message : String(e));
|
|
103
201
|
}
|
|
104
202
|
});
|
|
105
203
|
}
|
|
@@ -129,15 +227,23 @@ class AdminClient {
|
|
|
129
227
|
});
|
|
130
228
|
const batches = (0, batch_1.batch)(workflowRequests, batchSize, (_a = this.config.grpc_max_send_message_length) !== null && _a !== void 0 ? _a : 4 * 1024 * 1024);
|
|
131
229
|
this.logger.debug(`batching ${batches.length} batches`);
|
|
230
|
+
let bulkTrailerMetadata;
|
|
132
231
|
try {
|
|
133
232
|
const results = [];
|
|
134
233
|
// for loop to ensure serial execution of batches
|
|
135
234
|
for (const { payloads, originalIndices, batchIndex } of batches) {
|
|
136
|
-
const request =
|
|
235
|
+
const request = workflows_2.BulkTriggerWorkflowRequest.create({
|
|
137
236
|
workflows: payloads,
|
|
138
237
|
});
|
|
139
238
|
// Call the bulk trigger workflow method for this batch
|
|
140
|
-
const bulkTriggerWorkflowResponse = yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () {
|
|
239
|
+
const bulkTriggerWorkflowResponse = yield (0, retrier_1.retrier)(() => __awaiter(this, void 0, void 0, function* () {
|
|
240
|
+
return this.workflowsGrpc.bulkTriggerWorkflow(request, {
|
|
241
|
+
onTrailer: (trailer) => {
|
|
242
|
+
bulkTrailerMetadata = trailer;
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}), this.logger, undefined, undefined, (e) => !isNiceGrpcAlreadyExists(e) &&
|
|
246
|
+
!(isGrpcServiceError(e) && e.code === grpc_js_1.status.ALREADY_EXISTS));
|
|
141
247
|
this.logger.debug(`batch ${batchIndex + 1} of ${batches.length}`);
|
|
142
248
|
// Map the results back to their original indices
|
|
143
249
|
const batchResults = bulkTriggerWorkflowResponse.workflowRunIds.map((resp, index) => {
|
|
@@ -150,7 +256,17 @@ class AdminClient {
|
|
|
150
256
|
return results;
|
|
151
257
|
}
|
|
152
258
|
catch (e) {
|
|
153
|
-
|
|
259
|
+
if (isGrpcServiceError(e) && e.code === grpc_js_1.status.ALREADY_EXISTS) {
|
|
260
|
+
const collision = extractBulkTriggerCollisionFromGrpcError(e);
|
|
261
|
+
if (collision)
|
|
262
|
+
throw collision;
|
|
263
|
+
}
|
|
264
|
+
if (isNiceGrpcAlreadyExists(e)) {
|
|
265
|
+
const collision = extractBulkTriggerCollisionFromNiceGrpcMetadata(bulkTrailerMetadata);
|
|
266
|
+
if (collision)
|
|
267
|
+
throw collision;
|
|
268
|
+
}
|
|
269
|
+
throw new hatchet_error_1.default(e instanceof Error ? e.message : String(e));
|
|
154
270
|
}
|
|
155
271
|
});
|
|
156
272
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module Context
|
|
9
9
|
*/
|
|
10
10
|
import { Priority, RunOpts, TaskWorkflowDeclaration, BaseWorkflowDeclaration as WorkflowV1 } from '../../declaration';
|
|
11
|
-
import { Action } from '../../../clients/dispatcher/action-listener';
|
|
11
|
+
import type { Action } from '../../../clients/dispatcher/action-listener';
|
|
12
12
|
import { Logger, LogLevel } from '../../../util/logger';
|
|
13
13
|
import WorkflowRunRef from '../../../util/workflow-run-ref';
|
|
14
14
|
import { Conditions } from '../../conditions';
|
|
@@ -144,8 +144,15 @@ export declare class Context<T, K = {}> {
|
|
|
144
144
|
/**
|
|
145
145
|
* Gets the name of the current workflow.
|
|
146
146
|
* @returns The name of the workflow.
|
|
147
|
+
* @deprecated This method returns the task name. Use {@link workflowNameV1} for the workflow
|
|
148
|
+
* name or {@link taskName} for the task name.
|
|
147
149
|
*/
|
|
148
150
|
workflowName(): string;
|
|
151
|
+
/**
|
|
152
|
+
* Gets the name of the current workflow.
|
|
153
|
+
* @returns The name of the workflow.
|
|
154
|
+
*/
|
|
155
|
+
workflowNameV1(): string;
|
|
149
156
|
/**
|
|
150
157
|
* Gets the user data associated with the workflow.
|
|
151
158
|
* @returns The user data.
|
|
@@ -24,6 +24,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
24
24
|
exports.DurableContext = exports.Context = exports.ContextWorker = void 0;
|
|
25
25
|
const declaration_1 = require("../../declaration");
|
|
26
26
|
const hatchet_error_1 = __importDefault(require("../../../util/errors/hatchet-error"));
|
|
27
|
+
const action_listener_1 = require("../../../clients/dispatcher/action-listener");
|
|
27
28
|
const parse_1 = require("../../../util/parse");
|
|
28
29
|
const conditions_1 = require("../../conditions");
|
|
29
30
|
const transformer_1 = require("../../conditions/transformer");
|
|
@@ -210,10 +211,19 @@ class Context {
|
|
|
210
211
|
/**
|
|
211
212
|
* Gets the name of the current workflow.
|
|
212
213
|
* @returns The name of the workflow.
|
|
214
|
+
* @deprecated This method returns the task name. Use {@link workflowNameV1} for the workflow
|
|
215
|
+
* name or {@link taskName} for the task name.
|
|
213
216
|
*/
|
|
214
217
|
workflowName() {
|
|
215
218
|
return this.action.jobName;
|
|
216
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Gets the name of the current workflow.
|
|
222
|
+
* @returns The name of the workflow.
|
|
223
|
+
*/
|
|
224
|
+
workflowNameV1() {
|
|
225
|
+
return (0, action_listener_1.workflowNameFromAction)(this.action);
|
|
226
|
+
}
|
|
217
227
|
/**
|
|
218
228
|
* Gets the user data associated with the workflow.
|
|
219
229
|
* @returns The user data.
|
|
@@ -288,7 +298,7 @@ class Context {
|
|
|
288
298
|
return Promise.resolve();
|
|
289
299
|
}
|
|
290
300
|
const logger = this.v1.config.logger('ctx', this.v1.config.log_level);
|
|
291
|
-
const contextExtra = Object.assign({ workflowRunId: this.action.workflowRunId, taskRunExternalId: this.action.taskRunExternalId, retryCount: this.action.retryCount, workflowName: this.
|
|
301
|
+
const contextExtra = Object.assign({ workflowRunId: this.action.workflowRunId, taskRunExternalId: this.action.taskRunExternalId, retryCount: this.action.retryCount, workflowName: this.workflowNameV1() }, extra === null || extra === void 0 ? void 0 : extra.extra);
|
|
292
302
|
const promises = [];
|
|
293
303
|
if (!level || level === 'INFO') {
|
|
294
304
|
promises.push(logger.info(message, contextExtra));
|
|
@@ -335,6 +335,12 @@ class InternalWorker {
|
|
|
335
335
|
expression: f.expression,
|
|
336
336
|
payload: f.payload ? new TextEncoder().encode(JSON.stringify(f.payload)) : undefined,
|
|
337
337
|
}))) !== null && _w !== void 0 ? _w : [],
|
|
338
|
+
idempotency: workflow.idempotency
|
|
339
|
+
? {
|
|
340
|
+
expression: workflow.idempotency.expression,
|
|
341
|
+
ttlMs: workflow.idempotency.ttlMs,
|
|
342
|
+
}
|
|
343
|
+
: undefined,
|
|
338
344
|
});
|
|
339
345
|
this.registeredWorkflowPromises.push(registeredWorkflow);
|
|
340
346
|
yield registeredWorkflow;
|
package/v1/declaration.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import WorkflowRunRef from '../util/workflow-run-ref';
|
|
|
9
9
|
import { CronWorkflows, ScheduledWorkflows, V1CreateFilterRequest } from '../clients/rest/generated/data-contracts';
|
|
10
10
|
import * as z from 'zod/v4';
|
|
11
11
|
import { IHatchetClient } from './client/client.interface';
|
|
12
|
-
import { CreateWorkflowTaskOpts, CreateOnFailureTaskOpts, TaskFn, CreateWorkflowDurableTaskOpts, CreateBaseTaskOpts, CreateOnSuccessTaskOpts, Concurrency, DurableTaskFn, WorkerLabelComparator } from './task';
|
|
12
|
+
import { CreateWorkflowTaskOpts, CreateOnFailureTaskOpts, TaskFn, CreateWorkflowDurableTaskOpts, CreateBaseTaskOpts, CreateOnSuccessTaskOpts, Concurrency, DurableTaskFn, WorkerLabelComparator, IdempotencyConfig } from './task';
|
|
13
13
|
import { Duration } from './client/duration';
|
|
14
14
|
import { MetricsClient } from './client/features/metrics';
|
|
15
15
|
import { InputType, OutputType, UnknownInputType, JsonObject, Resolved } from './types';
|
|
@@ -152,6 +152,11 @@ export type CreateBaseWorkflowOpts = {
|
|
|
152
152
|
* can be used on the dashboard for autocomplete.
|
|
153
153
|
*/
|
|
154
154
|
inputValidator?: z.ZodType<any>;
|
|
155
|
+
/**
|
|
156
|
+
* (optional) idempotency configuration for the workflow.
|
|
157
|
+
* Prevents more than one run from occurring for a given key within the TTL window.
|
|
158
|
+
*/
|
|
159
|
+
idempotency?: IdempotencyConfig;
|
|
155
160
|
};
|
|
156
161
|
export type CreateTaskWorkflowOpts<I extends InputType = UnknownInputType, O extends OutputType = void> = CreateBaseWorkflowOpts & CreateBaseTaskOpts<I, O, TaskFn<I, O>>;
|
|
157
162
|
export type CreateDurableTaskWorkflowOpts<I extends InputType = UnknownInputType, O extends OutputType = void> = CreateBaseWorkflowOpts & CreateBaseTaskOpts<I, O, DurableTaskFn<I, O>> & {
|