@emmvish/stable-request 1.6.5 → 1.7.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/README.md +353 -1
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +4 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/core/stable-request.d.ts.map +1 -1
- package/dist/core/stable-request.js +13 -13
- package/dist/core/stable-request.js.map +1 -1
- package/dist/core/stable-workflow.d.ts.map +1 -1
- package/dist/core/stable-workflow.js +3 -3
- package/dist/core/stable-workflow.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +21 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utilities/execute-branch-workflow.d.ts.map +1 -1
- package/dist/utilities/execute-branch-workflow.js +11 -11
- package/dist/utilities/execute-branch-workflow.js.map +1 -1
- package/dist/utilities/execute-non-linear-workflow.d.ts.map +1 -1
- package/dist/utilities/execute-non-linear-workflow.js +9 -9
- package/dist/utilities/execute-non-linear-workflow.js.map +1 -1
- package/dist/utilities/execute-phase.d.ts.map +1 -1
- package/dist/utilities/execute-phase.js +3 -3
- package/dist/utilities/execute-phase.js.map +1 -1
- package/dist/utilities/execute-with-persistence.d.ts +3 -0
- package/dist/utilities/execute-with-persistence.d.ts.map +1 -0
- package/dist/utilities/execute-with-persistence.js +34 -0
- package/dist/utilities/execute-with-persistence.js.map +1 -0
- package/dist/utilities/get-new-delay-time.d.ts +1 -1
- package/dist/utilities/get-new-delay-time.d.ts.map +1 -1
- package/dist/utilities/get-new-delay-time.js +16 -5
- package/dist/utilities/get-new-delay-time.js.map +1 -1
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/index.js +1 -0
- package/dist/utilities/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ A production-grade HTTP Workflow Execution Engine for Node.js that transforms un
|
|
|
25
25
|
- [Config Cascading](#config-cascading)
|
|
26
26
|
- [Request Grouping](#request-grouping)
|
|
27
27
|
- [Shared Buffer and Pre-Execution Hooks](#shared-buffer-and-pre-execution-hooks)
|
|
28
|
+
- [State Persistence and Recovery](#state-persistence-and-recovery)
|
|
28
29
|
- [Comprehensive Observability](#comprehensive-observability)
|
|
29
30
|
- [Trial Mode](#trial-mode)
|
|
30
31
|
- [Common Use Cases](#common-use-cases)
|
|
@@ -853,6 +854,160 @@ console.log(sharedBuffer); // Updated with data from workfl
|
|
|
853
854
|
}
|
|
854
855
|
```
|
|
855
856
|
|
|
857
|
+
### State Persistence and Recovery
|
|
858
|
+
|
|
859
|
+
Persist workflow state to external storage for recovery, distributed coordination, and long-running workflows.
|
|
860
|
+
|
|
861
|
+
**How It Works**:
|
|
862
|
+
The persistence function operates in two modes:
|
|
863
|
+
- **LOAD Mode**: When `buffer` is empty/null, return the stored state
|
|
864
|
+
- **STORE Mode**: When `buffer` contains data, save it to your storage
|
|
865
|
+
|
|
866
|
+
**Redis Persistence with Distributed Locking**:
|
|
867
|
+
|
|
868
|
+
```typescript
|
|
869
|
+
import Redis from 'ioredis';
|
|
870
|
+
|
|
871
|
+
const redis = new Redis();
|
|
872
|
+
|
|
873
|
+
const persistToRedis = async ({ executionContext, params, buffer }) => {
|
|
874
|
+
const { workflowId, phaseId } = executionContext;
|
|
875
|
+
const { ttl = 86400, enableLocking = false } = params || {};
|
|
876
|
+
|
|
877
|
+
const stateKey = `workflow:${workflowId}:${phaseId}`;
|
|
878
|
+
const lockKey = `lock:${stateKey}`;
|
|
879
|
+
const isStoring = buffer && Object.keys(buffer).length > 0;
|
|
880
|
+
|
|
881
|
+
if (enableLocking) {
|
|
882
|
+
await redis.setex(lockKey, 5, Date.now().toString());
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
try {
|
|
886
|
+
if (isStoring) {
|
|
887
|
+
// STORE MODE: Save with metadata
|
|
888
|
+
const stateWithMeta = {
|
|
889
|
+
...buffer,
|
|
890
|
+
_meta: {
|
|
891
|
+
timestamp: new Date().toISOString(),
|
|
892
|
+
version: (buffer._meta?.version || 0) + 1
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
await redis.setex(stateKey, ttl, JSON.stringify(stateWithMeta));
|
|
896
|
+
console.log(`💾 State saved (v${stateWithMeta._meta.version})`);
|
|
897
|
+
} else {
|
|
898
|
+
// LOAD MODE: Retrieve state
|
|
899
|
+
const data = await redis.get(stateKey);
|
|
900
|
+
return data ? JSON.parse(data) : {};
|
|
901
|
+
}
|
|
902
|
+
} finally {
|
|
903
|
+
if (enableLocking) {
|
|
904
|
+
await redis.del(lockKey); // Release lock
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
return {};
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
// Use with workflow-level persistence (applies to all phases)
|
|
912
|
+
await stableWorkflow(phases, {
|
|
913
|
+
workflowId: 'distributed-job-456',
|
|
914
|
+
commonStatePersistence: {
|
|
915
|
+
persistenceFunction: persistToRedis,
|
|
916
|
+
persistenceParams: {
|
|
917
|
+
ttl: 3600,
|
|
918
|
+
enableLocking: true // Enable distributed locking
|
|
919
|
+
},
|
|
920
|
+
loadBeforeHooks: true,
|
|
921
|
+
storeAfterHooks: true
|
|
922
|
+
},
|
|
923
|
+
commonRequestData: { hostname: 'api.example.com' }
|
|
924
|
+
});
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
**Checkpoint-Based Recovery Pattern**:
|
|
928
|
+
|
|
929
|
+
```typescript
|
|
930
|
+
const createCheckpoint = async ({ executionContext, params, buffer }) => {
|
|
931
|
+
const { workflowId } = executionContext;
|
|
932
|
+
const checkpointKey = `checkpoint:${workflowId}`;
|
|
933
|
+
|
|
934
|
+
if (buffer && Object.keys(buffer).length > 0) {
|
|
935
|
+
// STORE: Save checkpoint with completed phases
|
|
936
|
+
const existing = JSON.parse(await redis.get(checkpointKey) || '{}');
|
|
937
|
+
const checkpoint = {
|
|
938
|
+
...existing,
|
|
939
|
+
completedPhases: [...new Set([
|
|
940
|
+
...(existing.completedPhases || []),
|
|
941
|
+
...(buffer.completedPhases || [])
|
|
942
|
+
])],
|
|
943
|
+
progress: buffer.progress || existing.progress || 0,
|
|
944
|
+
lastUpdated: new Date().toISOString()
|
|
945
|
+
};
|
|
946
|
+
await redis.setex(checkpointKey, 7200, JSON.stringify(checkpoint));
|
|
947
|
+
} else {
|
|
948
|
+
// LOAD: Return checkpoint data
|
|
949
|
+
const data = await redis.get(checkpointKey);
|
|
950
|
+
return data ? JSON.parse(data) : { completedPhases: [] };
|
|
951
|
+
}
|
|
952
|
+
return {};
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
const phases = [
|
|
956
|
+
{
|
|
957
|
+
id: 'phase-1',
|
|
958
|
+
requests: [...],
|
|
959
|
+
phaseDecisionHook: async ({ phaseResult, sharedBuffer }) => {
|
|
960
|
+
// Skip if already completed (recovery scenario)
|
|
961
|
+
if (sharedBuffer.completedPhases?.includes('phase-1')) {
|
|
962
|
+
console.log('✅ Phase-1 already completed, skipping...');
|
|
963
|
+
return {
|
|
964
|
+
action: PHASE_DECISION_ACTIONS.SKIP,
|
|
965
|
+
skipToPhaseId: 'phase-2'
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
if (phaseResult.success) {
|
|
970
|
+
sharedBuffer.completedPhases = [
|
|
971
|
+
...(sharedBuffer.completedPhases || []),
|
|
972
|
+
'phase-1'
|
|
973
|
+
];
|
|
974
|
+
return { action: PHASE_DECISION_ACTIONS.CONTINUE };
|
|
975
|
+
}
|
|
976
|
+
return { action: PHASE_DECISION_ACTIONS.TERMINATE };
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
id: 'phase-2',
|
|
981
|
+
requests: [...],
|
|
982
|
+
phaseDecisionHook: async ({ phaseResult, sharedBuffer }) => {
|
|
983
|
+
if (sharedBuffer.completedPhases?.includes('phase-2')) {
|
|
984
|
+
return { action: PHASE_DECISION_ACTIONS.CONTINUE };
|
|
985
|
+
}
|
|
986
|
+
if (phaseResult.success) {
|
|
987
|
+
sharedBuffer.completedPhases = [
|
|
988
|
+
...(sharedBuffer.completedPhases || []),
|
|
989
|
+
'phase-2'
|
|
990
|
+
];
|
|
991
|
+
}
|
|
992
|
+
return { action: PHASE_DECISION_ACTIONS.CONTINUE };
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
];
|
|
996
|
+
|
|
997
|
+
await stableWorkflow(phases, {
|
|
998
|
+
workflowId: 'resumable-workflow-789',
|
|
999
|
+
enableNonLinearExecution: true,
|
|
1000
|
+
sharedBuffer: { completedPhases: [] },
|
|
1001
|
+
commonStatePersistence: {
|
|
1002
|
+
persistenceFunction: createCheckpoint,
|
|
1003
|
+
persistenceParams: { ttl: 7200 },
|
|
1004
|
+
loadBeforeHooks: true,
|
|
1005
|
+
storeAfterHooks: true
|
|
1006
|
+
},
|
|
1007
|
+
commonRequestData: { hostname: 'api.example.com' }
|
|
1008
|
+
});
|
|
1009
|
+
```
|
|
1010
|
+
|
|
856
1011
|
### Comprehensive Observability
|
|
857
1012
|
|
|
858
1013
|
Built-in hooks for monitoring, logging, and analysis at every level:
|
|
@@ -1162,6 +1317,203 @@ async function sendWebhook(eventData: any) {
|
|
|
1162
1317
|
}
|
|
1163
1318
|
```
|
|
1164
1319
|
|
|
1320
|
+
### Distributed Data Migration with State Persistence
|
|
1321
|
+
|
|
1322
|
+
```typescript
|
|
1323
|
+
import Redis from 'ioredis';
|
|
1324
|
+
import {
|
|
1325
|
+
stableWorkflow,
|
|
1326
|
+
PHASE_DECISION_ACTIONS,
|
|
1327
|
+
REQUEST_METHODS,
|
|
1328
|
+
VALID_REQUEST_PROTOCOLS
|
|
1329
|
+
} from '@emmvish/stable-request';
|
|
1330
|
+
|
|
1331
|
+
const redis = new Redis();
|
|
1332
|
+
|
|
1333
|
+
// Checkpoint persistence for recovery
|
|
1334
|
+
const createCheckpoint = async ({ executionContext, buffer }) => {
|
|
1335
|
+
const { workflowId, phaseId } = executionContext;
|
|
1336
|
+
const key = `checkpoint:${workflowId}`;
|
|
1337
|
+
|
|
1338
|
+
if (buffer && Object.keys(buffer).length > 0) {
|
|
1339
|
+
// Save checkpoint with progress
|
|
1340
|
+
const existing = JSON.parse(await redis.get(key) || '{}');
|
|
1341
|
+
const checkpoint = {
|
|
1342
|
+
...existing,
|
|
1343
|
+
...buffer,
|
|
1344
|
+
completedPhases: [...new Set([
|
|
1345
|
+
...(existing.completedPhases || []),
|
|
1346
|
+
...(buffer.completedPhases || [])
|
|
1347
|
+
])],
|
|
1348
|
+
lastPhase: phaseId,
|
|
1349
|
+
updatedAt: new Date().toISOString()
|
|
1350
|
+
};
|
|
1351
|
+
await redis.setex(key, 86400, JSON.stringify(checkpoint));
|
|
1352
|
+
console.log(`💾 Checkpoint: ${checkpoint.recordsProcessed}/${checkpoint.totalRecords} records`);
|
|
1353
|
+
} else {
|
|
1354
|
+
// Load checkpoint
|
|
1355
|
+
const data = await redis.get(key);
|
|
1356
|
+
return data ? JSON.parse(data) : {
|
|
1357
|
+
completedPhases: [],
|
|
1358
|
+
recordsProcessed: 0,
|
|
1359
|
+
totalRecords: 0
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
return {};
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1365
|
+
const migrationPhases = [
|
|
1366
|
+
{
|
|
1367
|
+
id: 'extract',
|
|
1368
|
+
requests: [{
|
|
1369
|
+
id: 'fetch-data',
|
|
1370
|
+
requestOptions: {
|
|
1371
|
+
reqData: {
|
|
1372
|
+
protocol: VALID_REQUEST_PROTOCOLS.HTTPS,
|
|
1373
|
+
hostname: 'source-api.example.com',
|
|
1374
|
+
path: '/data',
|
|
1375
|
+
method: REQUEST_METHODS.GET
|
|
1376
|
+
},
|
|
1377
|
+
resReq: true
|
|
1378
|
+
}
|
|
1379
|
+
}],
|
|
1380
|
+
phaseDecisionHook: async ({ phaseResult, sharedBuffer }) => {
|
|
1381
|
+
if (sharedBuffer.completedPhases?.includes('extract')) {
|
|
1382
|
+
console.log('✅ Extract already completed, skipping...');
|
|
1383
|
+
return {
|
|
1384
|
+
action: PHASE_DECISION_ACTIONS.SKIP,
|
|
1385
|
+
skipToPhaseId: 'transform'
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
if (phaseResult.success) {
|
|
1390
|
+
const records = phaseResult.responses[0]?.data?.records || [];
|
|
1391
|
+
sharedBuffer.extractedData = records;
|
|
1392
|
+
sharedBuffer.totalRecords = records.length;
|
|
1393
|
+
sharedBuffer.completedPhases = ['extract'];
|
|
1394
|
+
return { action: PHASE_DECISION_ACTIONS.CONTINUE };
|
|
1395
|
+
}
|
|
1396
|
+
return { action: PHASE_DECISION_ACTIONS.TERMINATE };
|
|
1397
|
+
}
|
|
1398
|
+
},
|
|
1399
|
+
{
|
|
1400
|
+
id: 'transform',
|
|
1401
|
+
allowReplay: true,
|
|
1402
|
+
maxReplayCount: 3,
|
|
1403
|
+
requests: [{
|
|
1404
|
+
id: 'transform-batch',
|
|
1405
|
+
requestOptions: {
|
|
1406
|
+
reqData: {
|
|
1407
|
+
protocol: VALID_REQUEST_PROTOCOLS.HTTPS,
|
|
1408
|
+
hostname: 'transform-api.example.com',
|
|
1409
|
+
path: '/transform',
|
|
1410
|
+
method: REQUEST_METHODS.POST
|
|
1411
|
+
},
|
|
1412
|
+
resReq: true,
|
|
1413
|
+
preExecution: {
|
|
1414
|
+
preExecutionHook: ({ commonBuffer }) => {
|
|
1415
|
+
// Process in batches
|
|
1416
|
+
const batchSize = 100;
|
|
1417
|
+
const processed = commonBuffer.recordsProcessed || 0;
|
|
1418
|
+
const batch = commonBuffer.extractedData.slice(
|
|
1419
|
+
processed,
|
|
1420
|
+
processed + batchSize
|
|
1421
|
+
);
|
|
1422
|
+
return {
|
|
1423
|
+
reqData: { body: { records: batch } }
|
|
1424
|
+
};
|
|
1425
|
+
},
|
|
1426
|
+
applyPreExecutionConfigOverride: true
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}],
|
|
1430
|
+
phaseDecisionHook: async ({ phaseResult, sharedBuffer }) => {
|
|
1431
|
+
if (sharedBuffer.completedPhases?.includes('transform')) {
|
|
1432
|
+
return {
|
|
1433
|
+
action: PHASE_DECISION_ACTIONS.SKIP,
|
|
1434
|
+
skipToPhaseId: 'load'
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
if (phaseResult.success) {
|
|
1439
|
+
const transformed = phaseResult.responses[0]?.data?.transformed || [];
|
|
1440
|
+
sharedBuffer.recordsProcessed =
|
|
1441
|
+
(sharedBuffer.recordsProcessed || 0) + transformed.length;
|
|
1442
|
+
|
|
1443
|
+
// Continue transforming if more records remain
|
|
1444
|
+
if (sharedBuffer.recordsProcessed < sharedBuffer.totalRecords) {
|
|
1445
|
+
console.log(
|
|
1446
|
+
`🔄 Progress: ${sharedBuffer.recordsProcessed}/${sharedBuffer.totalRecords}`
|
|
1447
|
+
);
|
|
1448
|
+
return { action: PHASE_DECISION_ACTIONS.REPLAY };
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// All records transformed
|
|
1452
|
+
sharedBuffer.completedPhases = [
|
|
1453
|
+
...(sharedBuffer.completedPhases || []),
|
|
1454
|
+
'transform'
|
|
1455
|
+
];
|
|
1456
|
+
return { action: PHASE_DECISION_ACTIONS.CONTINUE };
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
return { action: PHASE_DECISION_ACTIONS.TERMINATE };
|
|
1460
|
+
}
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
id: 'load',
|
|
1464
|
+
requests: [{
|
|
1465
|
+
id: 'upload-data',
|
|
1466
|
+
requestOptions: {
|
|
1467
|
+
reqData: {
|
|
1468
|
+
protocol: VALID_REQUEST_PROTOCOLS.HTTPS,
|
|
1469
|
+
hostname: 'dest-api.example.com',
|
|
1470
|
+
path: '/import',
|
|
1471
|
+
method: REQUEST_METHODS.POST
|
|
1472
|
+
},
|
|
1473
|
+
resReq: false
|
|
1474
|
+
}
|
|
1475
|
+
}],
|
|
1476
|
+
phaseDecisionHook: async ({ phaseResult, sharedBuffer }) => {
|
|
1477
|
+
if (phaseResult.success) {
|
|
1478
|
+
sharedBuffer.completedPhases = [
|
|
1479
|
+
...(sharedBuffer.completedPhases || []),
|
|
1480
|
+
'load'
|
|
1481
|
+
];
|
|
1482
|
+
}
|
|
1483
|
+
return { action: PHASE_DECISION_ACTIONS.CONTINUE };
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
];
|
|
1487
|
+
|
|
1488
|
+
// Execute with state persistence for recovery
|
|
1489
|
+
const result = await stableWorkflow(migrationPhases, {
|
|
1490
|
+
workflowId: 'data-migration-2024-01-08',
|
|
1491
|
+
enableNonLinearExecution: true,
|
|
1492
|
+
sharedBuffer: {
|
|
1493
|
+
completedPhases: [],
|
|
1494
|
+
recordsProcessed: 0,
|
|
1495
|
+
totalRecords: 0
|
|
1496
|
+
},
|
|
1497
|
+
commonStatePersistence: {
|
|
1498
|
+
persistenceFunction: createCheckpoint,
|
|
1499
|
+
loadBeforeHooks: true,
|
|
1500
|
+
storeAfterHooks: true
|
|
1501
|
+
},
|
|
1502
|
+
commonAttempts: 3,
|
|
1503
|
+
commonWait: 2000,
|
|
1504
|
+
stopOnFirstPhaseError: true,
|
|
1505
|
+
logPhaseResults: true
|
|
1506
|
+
});
|
|
1507
|
+
|
|
1508
|
+
console.log(`✅ Migration completed: ${result.successfulRequests}/${result.totalRequests}`);
|
|
1509
|
+
console.log(`⏱️ Duration: ${result.executionTime}ms`);
|
|
1510
|
+
|
|
1511
|
+
// To resume a failed workflow, just re-run with the same workflowId
|
|
1512
|
+
// It will load the checkpoint and skip completed phases
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
---
|
|
1516
|
+
|
|
1165
1517
|
## License
|
|
1166
1518
|
|
|
1167
|
-
MIT © Manish Varma
|
|
1519
|
+
MIT © Manish Varma
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElF,eAAO,MAAM,wBAAwB,EAAE,CAAC,MAAM,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElF,eAAO,MAAM,wBAAwB,EAAE,CAAC,MAAM,mBAAmB,CAAC,EAqBjE,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,wBAAwB,EAqBrE,CAAC"}
|
package/dist/constants/index.js
CHANGED
|
@@ -12,11 +12,13 @@ export const extractCommonOptionsKeys = [
|
|
|
12
12
|
'commonPerformAllAttempts',
|
|
13
13
|
'commonWait',
|
|
14
14
|
'commonRetryStrategy',
|
|
15
|
+
'commonJitter',
|
|
15
16
|
'commonLogAllErrors',
|
|
16
17
|
'commonLogAllSuccessfulAttempts',
|
|
17
18
|
'commonMaxSerializableChars',
|
|
18
19
|
'commonTrialMode',
|
|
19
20
|
'commonCache',
|
|
21
|
+
'commonStatePersistence',
|
|
20
22
|
];
|
|
21
23
|
export const PrepareApiRequestOptionsMapping = [
|
|
22
24
|
{ localKey: 'preExecution', commonKey: 'commonPreExecution', groupCommonKey: 'commonPreExecution', targetKey: 'preExecution' },
|
|
@@ -27,6 +29,7 @@ export const PrepareApiRequestOptionsMapping = [
|
|
|
27
29
|
{ localKey: 'performAllAttempts', commonKey: 'commonPerformAllAttempts', groupCommonKey: 'commonPerformAllAttempts', targetKey: 'performAllAttempts' },
|
|
28
30
|
{ localKey: 'wait', commonKey: 'commonWait', groupCommonKey: 'commonWait', targetKey: 'wait' },
|
|
29
31
|
{ localKey: 'retryStrategy', commonKey: 'commonRetryStrategy', groupCommonKey: 'commonRetryStrategy', targetKey: 'retryStrategy' },
|
|
32
|
+
{ localKey: 'jitter', commonKey: 'commonJitter', groupCommonKey: 'commonJitter', targetKey: 'jitter' },
|
|
30
33
|
{ localKey: 'logAllErrors', commonKey: 'commonLogAllErrors', groupCommonKey: 'commonLogAllErrors', targetKey: 'logAllErrors' },
|
|
31
34
|
{ localKey: 'logAllSuccessfulAttempts', commonKey: 'commonLogAllSuccessfulAttempts', groupCommonKey: 'commonLogAllSuccessfulAttempts', targetKey: 'logAllSuccessfulAttempts' },
|
|
32
35
|
{ localKey: 'maxSerializableChars', commonKey: 'commonMaxSerializableChars', groupCommonKey: 'commonMaxSerializableChars', targetKey: 'maxSerializableChars' },
|
|
@@ -37,5 +40,6 @@ export const PrepareApiRequestOptionsMapping = [
|
|
|
37
40
|
{ localKey: 'finalErrorAnalyzer', commonKey: 'commonFinalErrorAnalyzer', groupCommonKey: 'commonFinalErrorAnalyzer', targetKey: 'finalErrorAnalyzer' },
|
|
38
41
|
{ localKey: 'cache', commonKey: 'commonCache', groupCommonKey: 'commonCache', targetKey: 'cache' },
|
|
39
42
|
{ localKey: 'commonBuffer', commonKey: 'sharedBuffer', groupCommonKey: 'sharedBuffer', targetKey: 'commonBuffer' },
|
|
43
|
+
{ localKey: 'statePersistence', commonKey: 'commonStatePersistence', groupCommonKey: 'commonStatePersistence', targetKey: 'statePersistence' },
|
|
40
44
|
];
|
|
41
45
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,wBAAwB,GAAkC;IACnE,oBAAoB;IACpB,kBAAkB;IAClB,sBAAsB;IACtB,mBAAmB;IACnB,wBAAwB;IACxB,oBAAoB;IACpB,mCAAmC;IACnC,0BAA0B;IAC1B,cAAc;IACd,gBAAgB;IAChB,0BAA0B;IAC1B,YAAY;IACZ,qBAAqB;IACrB,oBAAoB;IACpB,gCAAgC;IAChC,4BAA4B;IAC5B,iBAAiB;IACjB,aAAa;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stable-request.d.ts","sourceRoot":"","sources":["../../src/core/stable-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAe3B,wBAAsB,aAAa,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAC/E,OAAO,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,GACzD,OAAO,CAAC,gBAAgB,GAAG,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"stable-request.d.ts","sourceRoot":"","sources":["../../src/core/stable-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAe3B,wBAAsB,aAAa,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAC/E,OAAO,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,GACzD,OAAO,CAAC,gBAAgB,GAAG,OAAO,CAAC,CAkVrC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RETRY_STRATEGIES, RESPONSE_ERRORS, CircuitBreakerState } from '../enums/index.js';
|
|
2
|
-
import { CircuitBreaker, CircuitBreakerOpenError, formatLogContext, generateAxiosRequestConfig, getNewDelayTime, delay, reqFn,
|
|
2
|
+
import { CircuitBreaker, CircuitBreakerOpenError, executeWithPersistence, formatLogContext, generateAxiosRequestConfig, getNewDelayTime, delay, reqFn, safelyStringify, validateTrialModeProbabilities } from '../utilities/index.js';
|
|
3
3
|
export async function stableRequest(options) {
|
|
4
4
|
const { preExecution = {
|
|
5
5
|
preExecutionHook: ({ inputParams, commonBuffer }) => { },
|
|
@@ -9,10 +9,10 @@ export async function stableRequest(options) {
|
|
|
9
9
|
}, commonBuffer = {}, executionContext } = options;
|
|
10
10
|
let preExecutionResult;
|
|
11
11
|
try {
|
|
12
|
-
preExecutionResult = await
|
|
12
|
+
preExecutionResult = await executeWithPersistence(preExecution?.preExecutionHook, {
|
|
13
13
|
inputParams: preExecution?.preExecutionHookParams,
|
|
14
14
|
commonBuffer
|
|
15
|
-
});
|
|
15
|
+
}, options.statePersistence, executionContext || {}, commonBuffer);
|
|
16
16
|
if (preExecution?.applyPreExecutionConfigOverride) {
|
|
17
17
|
const finalOptions = {
|
|
18
18
|
...options,
|
|
@@ -26,7 +26,7 @@ export async function stableRequest(options) {
|
|
|
26
26
|
throw e;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
const { reqData: givenReqData, responseAnalyzer = ({ reqData, data, trialMode = { enabled: false } }) => true, resReq = false, attempts: givenAttempts = 1, performAllAttempts = false, wait = 1000, maxAllowedWait = 60000, retryStrategy = RETRY_STRATEGIES.FIXED, logAllErrors = false, handleErrors = ({ reqData, errorLog, maxSerializableChars = 1000, executionContext }) => console.error(`${formatLogContext(executionContext)}stable-request:\n`, 'Request data:\n', safelyStringify(reqData, maxSerializableChars), '\nError log:\n', safelyStringify(errorLog, maxSerializableChars)), logAllSuccessfulAttempts = false, handleSuccessfulAttemptData = ({ reqData, successfulAttemptData, maxSerializableChars = 1000, executionContext }) => console.info(`${formatLogContext(executionContext)}stable-request:\n`, 'Request data:\n', safelyStringify(reqData, maxSerializableChars), '\nSuccessful attempt:\n', safelyStringify(successfulAttemptData, maxSerializableChars)), maxSerializableChars = 1000, finalErrorAnalyzer = ({ reqData, error, trialMode = { enabled: false } }) => false, trialMode = { enabled: false }, hookParams = {}, cache, circuitBreaker } = options;
|
|
29
|
+
const { reqData: givenReqData, responseAnalyzer = ({ reqData, data, trialMode = { enabled: false } }) => true, resReq = false, attempts: givenAttempts = 1, performAllAttempts = false, wait = 1000, maxAllowedWait = 60000, retryStrategy = RETRY_STRATEGIES.FIXED, logAllErrors = false, handleErrors = ({ reqData, errorLog, maxSerializableChars = 1000, executionContext }) => console.error(`${formatLogContext(executionContext)}stable-request:\n`, 'Request data:\n', safelyStringify(reqData, maxSerializableChars), '\nError log:\n', safelyStringify(errorLog, maxSerializableChars)), logAllSuccessfulAttempts = false, handleSuccessfulAttemptData = ({ reqData, successfulAttemptData, maxSerializableChars = 1000, executionContext }) => console.info(`${formatLogContext(executionContext)}stable-request:\n`, 'Request data:\n', safelyStringify(reqData, maxSerializableChars), '\nSuccessful attempt:\n', safelyStringify(successfulAttemptData, maxSerializableChars)), maxSerializableChars = 1000, finalErrorAnalyzer = ({ reqData, error, trialMode = { enabled: false } }) => false, trialMode = { enabled: false }, hookParams = {}, cache, circuitBreaker, jitter = 0, statePersistence } = options;
|
|
30
30
|
let attempts = givenAttempts;
|
|
31
31
|
const reqData = generateAxiosRequestConfig(givenReqData);
|
|
32
32
|
let circuitBreakerInstance = null;
|
|
@@ -84,7 +84,7 @@ export async function stableRequest(options) {
|
|
|
84
84
|
let performNextAttempt = false;
|
|
85
85
|
if (res.ok) {
|
|
86
86
|
try {
|
|
87
|
-
performNextAttempt = !(await
|
|
87
|
+
performNextAttempt = !(await executeWithPersistence(responseAnalyzer, {
|
|
88
88
|
reqData,
|
|
89
89
|
data: res?.data,
|
|
90
90
|
trialMode,
|
|
@@ -92,7 +92,7 @@ export async function stableRequest(options) {
|
|
|
92
92
|
preExecutionResult,
|
|
93
93
|
commonBuffer,
|
|
94
94
|
executionContext
|
|
95
|
-
}));
|
|
95
|
+
}, statePersistence, executionContext || {}, commonBuffer));
|
|
96
96
|
}
|
|
97
97
|
catch (e) {
|
|
98
98
|
console.error(`${formatLogContext(executionContext)}stable-request: Unable to analyze the response returned on attempt #${currentAttempt}. Response: ${safelyStringify(res?.data, maxSerializableChars)}`);
|
|
@@ -125,7 +125,7 @@ export async function stableRequest(options) {
|
|
|
125
125
|
statusCode: res.statusCode
|
|
126
126
|
};
|
|
127
127
|
try {
|
|
128
|
-
await
|
|
128
|
+
await executeWithPersistence(handleErrors, {
|
|
129
129
|
reqData,
|
|
130
130
|
errorLog,
|
|
131
131
|
maxSerializableChars,
|
|
@@ -133,7 +133,7 @@ export async function stableRequest(options) {
|
|
|
133
133
|
preExecutionResult,
|
|
134
134
|
commonBuffer,
|
|
135
135
|
executionContext
|
|
136
|
-
});
|
|
136
|
+
}, statePersistence, executionContext || {}, commonBuffer);
|
|
137
137
|
}
|
|
138
138
|
catch (e) {
|
|
139
139
|
console.error(`${formatLogContext(executionContext)}stable-request: Unable to report errors due to issues with error handler! Error message provided by your handleErrors: ${safelyStringify(e.message, maxSerializableChars)}`);
|
|
@@ -151,7 +151,7 @@ export async function stableRequest(options) {
|
|
|
151
151
|
statusCode: res.statusCode
|
|
152
152
|
};
|
|
153
153
|
try {
|
|
154
|
-
await
|
|
154
|
+
await executeWithPersistence(handleSuccessfulAttemptData, {
|
|
155
155
|
reqData,
|
|
156
156
|
successfulAttemptData: successfulAttemptLog,
|
|
157
157
|
maxSerializableChars,
|
|
@@ -159,7 +159,7 @@ export async function stableRequest(options) {
|
|
|
159
159
|
preExecutionResult,
|
|
160
160
|
commonBuffer,
|
|
161
161
|
executionContext
|
|
162
|
-
});
|
|
162
|
+
}, statePersistence, executionContext || {}, commonBuffer);
|
|
163
163
|
}
|
|
164
164
|
catch (e) {
|
|
165
165
|
console.error(`${formatLogContext(executionContext)}stable-request: Unable to report successful attempts due to issues with successful attempt data handler! Error message provided by your handleSuccessfulAttemptData: ${safelyStringify(e.message, maxSerializableChars)}`);
|
|
@@ -173,7 +173,7 @@ export async function stableRequest(options) {
|
|
|
173
173
|
((!originalResOk && res.isRetryable) ||
|
|
174
174
|
(originalResOk && performNextAttempt) ||
|
|
175
175
|
performAllAttempts)) {
|
|
176
|
-
await delay(getNewDelayTime(retryStrategy, wait, currentAttempt), maxAllowedWait);
|
|
176
|
+
await delay(getNewDelayTime(retryStrategy, wait, currentAttempt, jitter), maxAllowedWait);
|
|
177
177
|
}
|
|
178
178
|
} while (attempts > 0 &&
|
|
179
179
|
((res.isRetryable && !res.ok) || performAllAttempts));
|
|
@@ -203,7 +203,7 @@ export async function stableRequest(options) {
|
|
|
203
203
|
}
|
|
204
204
|
let errorAnalysisResult = false;
|
|
205
205
|
try {
|
|
206
|
-
errorAnalysisResult = await
|
|
206
|
+
errorAnalysisResult = await executeWithPersistence(finalErrorAnalyzer, {
|
|
207
207
|
reqData,
|
|
208
208
|
error: e,
|
|
209
209
|
trialMode,
|
|
@@ -211,7 +211,7 @@ export async function stableRequest(options) {
|
|
|
211
211
|
preExecutionResult,
|
|
212
212
|
commonBuffer,
|
|
213
213
|
executionContext
|
|
214
|
-
});
|
|
214
|
+
}, statePersistence, executionContext || {}, commonBuffer);
|
|
215
215
|
}
|
|
216
216
|
catch (errorAnalysisError) {
|
|
217
217
|
console.error(`${formatLogContext(executionContext)}stable-request: Unable to analyze the final error returned. Error message provided by your finalErrorAnalyzer: ${safelyStringify(errorAnalysisError.message, maxSerializableChars)}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stable-request.js","sourceRoot":"","sources":["../../src/core/stable-request.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAU3B,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,KAAK,EACL,KAAK,EACL,
|
|
1
|
+
{"version":3,"file":"stable-request.js","sourceRoot":"","sources":["../../src/core/stable-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stable-workflow.d.ts","sourceRoot":"","sources":["../../src/core/stable-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,mBAAmB,CAAC;AAW3B,wBAAsB,cAAc,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAC9E,MAAM,EAAE,qBAAqB,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAE,EAClE,OAAO,GAAE,uBAAuB,CAAC,eAAe,EAAE,gBAAgB,CAAM,GACzE,OAAO,CAAC,sBAAsB,CAAC,gBAAgB,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"stable-workflow.d.ts","sourceRoot":"","sources":["../../src/core/stable-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,mBAAmB,CAAC;AAW3B,wBAAsB,cAAc,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAC9E,MAAM,EAAE,qBAAqB,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAE,EAClE,OAAO,GAAE,uBAAuB,CAAC,eAAe,EAAE,gBAAgB,CAAM,GACzE,OAAO,CAAC,sBAAsB,CAAC,gBAAgB,CAAC,CAAC,CAmdnD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { executeBranchWorkflow, executePhase, executeNonLinearWorkflow,
|
|
1
|
+
import { executeBranchWorkflow, executePhase, executeNonLinearWorkflow, executeWithPersistence, safelyStringify, CircuitBreaker, formatLogContext } from '../utilities/index.js';
|
|
2
2
|
export async function stableWorkflow(phases, options = {}) {
|
|
3
3
|
const { stopOnFirstPhaseError = false, logPhaseResults = false, handlePhaseCompletion = ({ workflowId, phaseResult, maxSerializableChars = 1000 }) => console.info('stable-request:\n', 'Workflow ID:\n', workflowId, '\nPhase result:\n', safelyStringify(phaseResult, maxSerializableChars)), handlePhaseError = ({ workflowId, error, phaseResult, maxSerializableChars = 1000 }) => console.error('stable-request:\n', 'Workflow ID:\n', workflowId, '\nError:\n', safelyStringify({ error, phaseResult }, maxSerializableChars)), handlePhaseDecision, handleBranchCompletion, handleBranchDecision, maxSerializableChars = 1000, requestGroups = [], workflowHookParams = {}, concurrentPhaseExecution = false, enableMixedExecution = false, enableBranchExecution = false, enableNonLinearExecution = false, maxWorkflowIterations = 1000, branches, ...commonGatewayOptions } = options;
|
|
4
4
|
const workflowStartTime = Date.now();
|
|
@@ -131,14 +131,14 @@ export async function stableWorkflow(phases, options = {}) {
|
|
|
131
131
|
console.error(`${formatLogContext({ workflowId, phaseId })}stable-request: Phase ${phaseId} failed:`, error);
|
|
132
132
|
}
|
|
133
133
|
try {
|
|
134
|
-
await
|
|
134
|
+
await executeWithPersistence(handlePhaseError, {
|
|
135
135
|
workflowId,
|
|
136
136
|
phaseResult,
|
|
137
137
|
error,
|
|
138
138
|
maxSerializableChars,
|
|
139
139
|
params: workflowHookParams?.handlePhaseErrorParams,
|
|
140
140
|
sharedBuffer: options.sharedBuffer
|
|
141
|
-
});
|
|
141
|
+
}, workflowHookParams?.statePersistence, { workflowId }, options.sharedBuffer || {});
|
|
142
142
|
}
|
|
143
143
|
catch (hookError) {
|
|
144
144
|
console.error(`stable-request: [Workflow: ${workflowId}] Error in handlePhaseError hook:`, hookError);
|