@emmvish/stable-request 2.2.0 → 2.2.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.
Files changed (38) hide show
  1. package/README.md +190 -0
  2. package/dist/constants/index.d.ts.map +1 -1
  3. package/dist/constants/index.js +1 -0
  4. package/dist/constants/index.js.map +1 -1
  5. package/dist/core/stable-function.d.ts.map +1 -1
  6. package/dist/core/stable-function.js +185 -169
  7. package/dist/core/stable-function.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/types/index.d.ts +2 -0
  13. package/dist/types/index.d.ts.map +1 -1
  14. package/dist/utilities/execute-branch-workflow.d.ts.map +1 -1
  15. package/dist/utilities/execute-branch-workflow.js +5 -1
  16. package/dist/utilities/execute-branch-workflow.js.map +1 -1
  17. package/dist/utilities/execute-phase.d.ts.map +1 -1
  18. package/dist/utilities/execute-phase.js +3 -0
  19. package/dist/utilities/execute-phase.js.map +1 -1
  20. package/dist/utilities/execute-sequentially.d.ts.map +1 -1
  21. package/dist/utilities/execute-sequentially.js +0 -1
  22. package/dist/utilities/execute-sequentially.js.map +1 -1
  23. package/dist/utilities/execute-with-timeout.d.ts +6 -0
  24. package/dist/utilities/execute-with-timeout.d.ts.map +1 -0
  25. package/dist/utilities/execute-with-timeout.js +28 -0
  26. package/dist/utilities/execute-with-timeout.js.map +1 -0
  27. package/dist/utilities/index.d.ts +1 -0
  28. package/dist/utilities/index.d.ts.map +1 -1
  29. package/dist/utilities/index.js +1 -0
  30. package/dist/utilities/index.js.map +1 -1
  31. package/dist/utilities/metrics-aggregator.d.ts +0 -36
  32. package/dist/utilities/metrics-aggregator.d.ts.map +1 -1
  33. package/dist/utilities/metrics-aggregator.js +1 -42
  34. package/dist/utilities/metrics-aggregator.js.map +1 -1
  35. package/dist/utilities/prepare-api-function-options.d.ts.map +1 -1
  36. package/dist/utilities/prepare-api-function-options.js +1 -0
  37. package/dist/utilities/prepare-api-function-options.js.map +1 -1
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -470,6 +470,196 @@ console.log(`Graph workflow success: ${result.success}`);
470
470
 
471
471
  ## Resilience Mechanisms
472
472
 
473
+ ### Execution Timeouts
474
+
475
+ Set maximum execution time for functions to prevent indefinite hangs. Timeouts are enforced at multiple levels with proper inheritance.
476
+
477
+ #### Function-Level Timeout
478
+
479
+ Set timeout directly on a function:
480
+
481
+ ```typescript
482
+ import { stableFunction } from '@emmvish/stable-request';
483
+
484
+ const result = await stableFunction({
485
+ fn: async () => {
486
+ // Long-running operation
487
+ await processLargeDataset();
488
+ return 'success';
489
+ },
490
+ args: [],
491
+ returnResult: true,
492
+ executionTimeout: 5000, // 5 seconds max
493
+ attempts: 3,
494
+ });
495
+
496
+ if (!result.success && result.error?.includes('timeout')) {
497
+ console.log('Function timed out');
498
+ }
499
+ ```
500
+
501
+ #### Gateway-Level Timeout
502
+
503
+ Apply timeout to all functions in a gateway:
504
+
505
+ ```typescript
506
+ import { stableApiGateway, RequestOrFunction } from '@emmvish/stable-request';
507
+
508
+ const results = await stableApiGateway(
509
+ [
510
+ {
511
+ type: RequestOrFunction.FUNCTION,
512
+ function: {
513
+ id: 'task1',
514
+ functionOptions: {
515
+ fn: async () => await task1(),
516
+ args: [],
517
+ // No timeout specified - inherits from gateway
518
+ },
519
+ },
520
+ },
521
+ {
522
+ type: RequestOrFunction.FUNCTION,
523
+ function: {
524
+ id: 'task2',
525
+ functionOptions: {
526
+ fn: async () => await task2(),
527
+ args: [],
528
+ executionTimeout: 10000, // Override gateway timeout
529
+ },
530
+ },
531
+ },
532
+ ],
533
+ {
534
+ commonExecutionTimeout: 3000, // Default 3s for all functions
535
+ }
536
+ );
537
+ ```
538
+
539
+ #### Request Group Timeout
540
+
541
+ Different timeouts for different groups:
542
+
543
+ ```typescript
544
+ const results = await stableApiGateway(
545
+ [
546
+ {
547
+ type: RequestOrFunction.FUNCTION,
548
+ function: {
549
+ id: 'critical',
550
+ groupId: 'criticalOps',
551
+ functionOptions: { fn: criticalOp, args: [] },
552
+ },
553
+ },
554
+ {
555
+ type: RequestOrFunction.FUNCTION,
556
+ function: {
557
+ id: 'background',
558
+ groupId: 'backgroundOps',
559
+ functionOptions: { fn: backgroundOp, args: [] },
560
+ },
561
+ },
562
+ ],
563
+ {
564
+ requestGroups: [
565
+ {
566
+ id: 'criticalOps',
567
+ commonConfig: {
568
+ commonExecutionTimeout: 1000, // Strict 1s timeout
569
+ },
570
+ },
571
+ {
572
+ id: 'backgroundOps',
573
+ commonConfig: {
574
+ commonExecutionTimeout: 30000, // Lenient 30s timeout
575
+ },
576
+ },
577
+ ],
578
+ }
579
+ );
580
+ ```
581
+
582
+ #### Workflow Phase Timeout
583
+
584
+ Apply timeout at phase level in workflows:
585
+
586
+ ```typescript
587
+ import { stableWorkflow } from '@emmvish/stable-request';
588
+
589
+ const result = await stableWorkflow(
590
+ [
591
+ {
592
+ id: 'initialization',
593
+ functions: [
594
+ {
595
+ id: 'init',
596
+ functionOptions: {
597
+ fn: initializeSystem,
598
+ args: [],
599
+ },
600
+ },
601
+ ],
602
+ commonConfig: {
603
+ commonExecutionTimeout: 5000, // 5s for initialization
604
+ },
605
+ },
606
+ {
607
+ id: 'processing',
608
+ functions: [
609
+ {
610
+ id: 'process',
611
+ functionOptions: {
612
+ fn: processData,
613
+ args: [],
614
+ },
615
+ },
616
+ ],
617
+ commonConfig: {
618
+ commonExecutionTimeout: 30000, // 30s for processing
619
+ },
620
+ },
621
+ ],
622
+ {
623
+ commonExecutionTimeout: 10000, // Default for phases without specific timeout
624
+ }
625
+ );
626
+ ```
627
+
628
+ #### Timeout Precedence
629
+
630
+ Timeouts follow the configuration cascade pattern:
631
+
632
+ **Function > Group > Phase/Branch > Gateway**
633
+
634
+ - Function-level `executionTimeout` always wins
635
+ - If not set, inherits from request group's `commonExecutionTimeout`
636
+ - If not set, inherits from phase/branch's `commonExecutionTimeout`
637
+ - If not set, inherits from gateway's `commonExecutionTimeout`
638
+ - If not set, no timeout is applied
639
+
640
+ #### Timeout Behavior
641
+
642
+ - Timeout applies to **entire function execution** including all retry attempts
643
+ - When timeout is exceeded, function returns failed result with timeout error
644
+ - Timeout does NOT stop execution mid-flight (no AbortController)
645
+ - Metrics are still collected even when timeout occurs
646
+ - Use with retries: timeout encompasses all attempts, not per-attempt
647
+
648
+ ```typescript
649
+ const result = await stableFunction({
650
+ fn: slowFunction,
651
+ args: [],
652
+ attempts: 5,
653
+ wait: 1000,
654
+ executionTimeout: 3000, // Total time for all 5 attempts
655
+ });
656
+
657
+ // If each attempt takes 800ms:
658
+ // - Attempt 1: 800ms
659
+ // - Attempt 2: starts at 1800ms (after 1s wait)
660
+ // - Attempt 3: would start at 3600ms → TIMEOUT at 3000ms
661
+ ```
662
+
473
663
  ### Retry Strategies
474
664
 
475
665
  When a request or function fails and is retryable, retry with configurable backoff.
@@ -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,EAqBjE,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,wBAAwB,EAqBrE,CAAC;AAEF,eAAO,MAAM,gCAAgC,gHAMnC,CAAC;AAEX,eAAO,MAAM,oCAAoC,2JASvC,CAAC;AAEX,eAAO,MAAM,iCAAiC,qPAapC,CAAC;AAEX,eAAO,MAAM,wCAAwC,6DAI3C,CAAC;AAEX,eAAO,MAAM,8BAA8B,2EAKjC,CAAC;AAEX,eAAO,MAAM,qCAAqC,2FAKxC,CAAC;AAEX,eAAO,MAAM,4CAA4C,2EAI/C,CAAC;AAEX,eAAO,MAAM,8BAA8B,iIAOjC,CAAC;AAEX,eAAO,MAAM,+BAA+B,oLAUlC,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,EAsBjE,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,wBAAwB,EAqBrE,CAAC;AAEF,eAAO,MAAM,gCAAgC,gHAMnC,CAAC;AAEX,eAAO,MAAM,oCAAoC,2JASvC,CAAC;AAEX,eAAO,MAAM,iCAAiC,qPAapC,CAAC;AAEX,eAAO,MAAM,wCAAwC,6DAI3C,CAAC;AAEX,eAAO,MAAM,8BAA8B,2EAKjC,CAAC;AAEX,eAAO,MAAM,qCAAqC,2FAKxC,CAAC;AAEX,eAAO,MAAM,4CAA4C,2EAI/C,CAAC;AAEX,eAAO,MAAM,8BAA8B,iIAOjC,CAAC;AAEX,eAAO,MAAM,+BAA+B,oLAUlC,CAAC"}
@@ -19,6 +19,7 @@ export const extractCommonOptionsKeys = [
19
19
  'commonTrialMode',
20
20
  'commonCache',
21
21
  'commonStatePersistence',
22
+ 'commonExecutionTimeout',
22
23
  ];
23
24
  export const PrepareApiRequestOptionsMapping = [
24
25
  { localKey: 'preExecution', commonKey: 'commonPreExecution', groupCommonKey: 'commonPreExecution', targetKey: 'preExecution' },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"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"}
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-function.d.ts","sourceRoot":"","sources":["../../src/core/stable-function.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,eAAe,EACf,sBAAsB,EAEvB,MAAM,mBAAmB,CAAC;AAmB3B,wBAAsB,cAAc,CAAC,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,OAAO,GAAG,GAAG,EAC7E,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CA8a1C"}
1
+ {"version":3,"file":"stable-function.d.ts","sourceRoot":"","sources":["../../src/core/stable-function.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,eAAe,EACf,sBAAsB,EAEvB,MAAM,mBAAmB,CAAC;AAqB3B,wBAAsB,cAAc,CAAC,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,OAAO,GAAG,GAAG,EAC7E,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAkc1C"}
@@ -1,5 +1,5 @@
1
1
  import { RETRY_STRATEGIES, CircuitBreakerState } from '../enums/index.js';
2
- import { CircuitBreaker, CircuitBreakerOpenError, executeWithPersistence, formatLogContext, getGlobalFunctionCacheManager, getNewDelayTime, delay, fnExec, safelyStringify, validateTrialModeProbabilities, MetricsAggregator, MetricsValidator, RateLimiter, ConcurrencyLimiter } from '../utilities/index.js';
2
+ import { CircuitBreaker, CircuitBreakerOpenError, executeWithPersistence, executeWithTimeout, TimeoutError, formatLogContext, getGlobalFunctionCacheManager, getNewDelayTime, delay, fnExec, safelyStringify, validateTrialModeProbabilities, MetricsAggregator, MetricsValidator, RateLimiter, ConcurrencyLimiter } from '../utilities/index.js';
3
3
  export async function stableFunction(options) {
4
4
  const { preExecution = {
5
5
  preExecutionHook: ({ inputParams, commonBuffer }) => { },
@@ -27,7 +27,7 @@ export async function stableFunction(options) {
27
27
  throw e;
28
28
  }
29
29
  }
30
- const { fn, args, responseAnalyzer = ({ data, trialMode = { enabled: false } }) => true, returnResult = false, attempts: givenAttempts = 1, performAllAttempts = false, wait = 1000, maxAllowedWait = 60000, retryStrategy = RETRY_STRATEGIES.FIXED, logAllErrors = false, handleErrors = ({ fn, args, errorLog, maxSerializableChars = 1000, executionContext }) => console.error(`${formatLogContext(executionContext)}stable-request:\n`, `Function: ${fn.name || 'anonymous'}\n`, 'Args:\n', safelyStringify(args, maxSerializableChars), '\nError log:\n', safelyStringify(errorLog, maxSerializableChars)), logAllSuccessfulAttempts = false, handleSuccessfulAttemptData = ({ fn, args, successfulAttemptData, maxSerializableChars = 1000, executionContext }) => console.info(`${formatLogContext(executionContext)}stable-request:\n`, `Function: ${fn.name || 'anonymous'}\n`, 'Args:\n', safelyStringify(args, maxSerializableChars), '\nSuccessful attempt:\n', safelyStringify(successfulAttemptData, maxSerializableChars)), maxSerializableChars = 1000, finalErrorAnalyzer = ({ fn, args, error, trialMode = { enabled: false } }) => false, trialMode = { enabled: false }, hookParams = {}, cache, circuitBreaker, jitter = 0, statePersistence, rateLimit, maxConcurrentRequests } = options;
30
+ const { fn, args, responseAnalyzer = ({ data, trialMode = { enabled: false } }) => true, returnResult = false, attempts: givenAttempts = 1, performAllAttempts = false, wait = 1000, maxAllowedWait = 60000, retryStrategy = RETRY_STRATEGIES.FIXED, logAllErrors = false, handleErrors = ({ fn, args, errorLog, maxSerializableChars = 1000, executionContext }) => console.error(`${formatLogContext(executionContext)}stable-request:\n`, `Function: ${fn.name || 'anonymous'}\n`, 'Args:\n', safelyStringify(args, maxSerializableChars), '\nError log:\n', safelyStringify(errorLog, maxSerializableChars)), logAllSuccessfulAttempts = false, handleSuccessfulAttemptData = ({ fn, args, successfulAttemptData, maxSerializableChars = 1000, executionContext }) => console.info(`${formatLogContext(executionContext)}stable-request:\n`, `Function: ${fn.name || 'anonymous'}\n`, 'Args:\n', safelyStringify(args, maxSerializableChars), '\nSuccessful attempt:\n', safelyStringify(successfulAttemptData, maxSerializableChars)), maxSerializableChars = 1000, finalErrorAnalyzer = ({ fn, args, error, trialMode = { enabled: false } }) => false, trialMode = { enabled: false }, hookParams = {}, cache, circuitBreaker, jitter = 0, statePersistence, rateLimit, maxConcurrentRequests, executionTimeout } = options;
31
31
  let attempts = givenAttempts;
32
32
  const functionStartTime = Date.now();
33
33
  const errorLogs = [];
@@ -76,210 +76,226 @@ export async function stableFunction(options) {
76
76
  if (maxConcurrentRequests && maxConcurrentRequests > 0) {
77
77
  concurrencyLimiterInstance = new ConcurrencyLimiter(maxConcurrentRequests);
78
78
  }
79
- try {
80
- validateTrialModeProbabilities(trialMode);
81
- let res = {
82
- ok: false,
83
- isRetryable: true,
84
- timestamp: new Date().toISOString(),
85
- executionTime: 0
86
- };
87
- const maxAttempts = attempts;
88
- let lastSuccessfulAttemptData = undefined;
89
- let hadAtLeastOneSuccess = false;
90
- do {
91
- attempts--;
92
- const currentAttempt = maxAttempts - attempts;
93
- totalAttemptsMade = currentAttempt;
94
- if (circuitBreakerInstance) {
95
- const cbConfig = circuitBreakerInstance.getState().config;
96
- if (cbConfig.trackIndividualAttempts || currentAttempt === 1) {
97
- const canExecute = await circuitBreakerInstance.canExecute();
98
- if (!canExecute) {
99
- throw new CircuitBreakerOpenError(`${formatLogContext(executionContext)}stable-request: Circuit breaker is ${circuitBreakerInstance.getState().state}. Function execution blocked at attempt ${currentAttempt}.`);
79
+ const executeFunction = async () => {
80
+ try {
81
+ validateTrialModeProbabilities(trialMode);
82
+ let res = {
83
+ ok: false,
84
+ isRetryable: true,
85
+ timestamp: new Date().toISOString(),
86
+ executionTime: 0
87
+ };
88
+ const maxAttempts = attempts;
89
+ let lastSuccessfulAttemptData = undefined;
90
+ let hadAtLeastOneSuccess = false;
91
+ do {
92
+ attempts--;
93
+ const currentAttempt = maxAttempts - attempts;
94
+ totalAttemptsMade = currentAttempt;
95
+ if (circuitBreakerInstance) {
96
+ const cbConfig = circuitBreakerInstance.getState().config;
97
+ if (cbConfig.trackIndividualAttempts || currentAttempt === 1) {
98
+ const canExecute = await circuitBreakerInstance.canExecute();
99
+ if (!canExecute) {
100
+ throw new CircuitBreakerOpenError(`${formatLogContext(executionContext)}stable-request: Circuit breaker is ${circuitBreakerInstance.getState().state}. Function execution blocked at attempt ${currentAttempt}.`);
101
+ }
100
102
  }
101
103
  }
102
- }
103
- try {
104
- const executeAttempt = async () => {
105
- return await fnExec(fn, args, returnResult, maxSerializableChars, trialMode, cache, executionContext);
106
- };
107
- if (rateLimiterInstance && concurrencyLimiterInstance) {
108
- res = await rateLimiterInstance.execute(() => concurrencyLimiterInstance.execute(executeAttempt));
109
- }
110
- else if (rateLimiterInstance) {
111
- res = await rateLimiterInstance.execute(executeAttempt);
112
- }
113
- else if (concurrencyLimiterInstance) {
114
- res = await concurrencyLimiterInstance.execute(executeAttempt);
115
- }
116
- else {
117
- res = await executeAttempt();
118
- }
119
- if (res.fromCache && res.ok) {
120
- if (trialMode.enabled) {
121
- console.info(`${formatLogContext(executionContext)}stable-request: Response served from cache:\n`, safelyStringify(res?.data, maxSerializableChars));
104
+ try {
105
+ const executeAttempt = async () => {
106
+ return await fnExec(fn, args, returnResult, maxSerializableChars, trialMode, cache, executionContext);
107
+ };
108
+ if (rateLimiterInstance && concurrencyLimiterInstance) {
109
+ res = await rateLimiterInstance.execute(() => concurrencyLimiterInstance.execute(executeAttempt));
110
+ }
111
+ else if (rateLimiterInstance) {
112
+ res = await rateLimiterInstance.execute(executeAttempt);
113
+ }
114
+ else if (concurrencyLimiterInstance) {
115
+ res = await concurrencyLimiterInstance.execute(executeAttempt);
116
+ }
117
+ else {
118
+ res = await executeAttempt();
119
+ }
120
+ if (res.fromCache && res.ok) {
121
+ if (trialMode.enabled) {
122
+ console.info(`${formatLogContext(executionContext)}stable-request: Response served from cache:\n`, safelyStringify(res?.data, maxSerializableChars));
123
+ }
124
+ return buildResult(true, returnResult ? res?.data : true);
122
125
  }
123
- return buildResult(true, returnResult ? res?.data : true);
124
126
  }
125
- }
126
- catch (attemptError) {
127
- if (attemptError instanceof CircuitBreakerOpenError) {
127
+ catch (attemptError) {
128
+ if (attemptError instanceof CircuitBreakerOpenError) {
129
+ throw attemptError;
130
+ }
131
+ if (circuitBreakerInstance && circuitBreakerInstance.getState().config.trackIndividualAttempts) {
132
+ circuitBreakerInstance.recordAttemptFailure();
133
+ if (circuitBreakerInstance.getState().state === CircuitBreakerState.OPEN) {
134
+ throw new CircuitBreakerOpenError(`${formatLogContext(executionContext)}stable-request: Circuit breaker opened after attempt ${currentAttempt}. No further retries.`);
135
+ }
136
+ }
128
137
  throw attemptError;
129
138
  }
130
- if (circuitBreakerInstance && circuitBreakerInstance.getState().config.trackIndividualAttempts) {
131
- circuitBreakerInstance.recordAttemptFailure();
132
- if (circuitBreakerInstance.getState().state === CircuitBreakerState.OPEN) {
133
- throw new CircuitBreakerOpenError(`${formatLogContext(executionContext)}stable-request: Circuit breaker opened after attempt ${currentAttempt}. No further retries.`);
139
+ const originalResOk = res.ok;
140
+ let performNextAttempt = false;
141
+ if (res.ok) {
142
+ try {
143
+ performNextAttempt = !(await executeWithPersistence(responseAnalyzer, {
144
+ fn,
145
+ args,
146
+ data: res?.data,
147
+ trialMode,
148
+ params: hookParams?.responseAnalyzerParams,
149
+ preExecutionResult,
150
+ commonBuffer,
151
+ executionContext
152
+ }, statePersistence, executionContext || {}, commonBuffer));
134
153
  }
135
- }
136
- throw attemptError;
137
- }
138
- const originalResOk = res.ok;
139
- let performNextAttempt = false;
140
- if (res.ok) {
141
- try {
142
- performNextAttempt = !(await executeWithPersistence(responseAnalyzer, {
143
- fn,
144
- args,
145
- data: res?.data,
146
- trialMode,
147
- params: hookParams?.responseAnalyzerParams,
148
- preExecutionResult,
149
- commonBuffer,
150
- executionContext
151
- }, statePersistence, executionContext || {}, commonBuffer));
152
- }
153
- catch (e) {
154
- console.error(`${formatLogContext(executionContext)}stable-request: Unable to analyze the response returned on attempt #${currentAttempt}. Response: ${safelyStringify(res?.data, maxSerializableChars)}`);
155
- console.error(`${formatLogContext(executionContext)}stable-request: Error message provided by your responseAnalyzer: ${safelyStringify(e.message, maxSerializableChars)}`);
156
- performNextAttempt = true;
157
- }
158
- }
159
- if (circuitBreakerInstance && circuitBreakerInstance.getState().config.trackIndividualAttempts) {
160
- if (res.ok && !performNextAttempt) {
161
- circuitBreakerInstance.recordAttemptSuccess();
162
- }
163
- else if (!res.ok || performNextAttempt) {
164
- circuitBreakerInstance.recordAttemptFailure();
165
- if (circuitBreakerInstance.getState().state === CircuitBreakerState.OPEN) {
166
- throw new CircuitBreakerOpenError(`${formatLogContext(executionContext)}stable-request: Circuit breaker opened after attempt ${currentAttempt}/${maxAttempts}. Blocking further retries.`);
154
+ catch (e) {
155
+ console.error(`${formatLogContext(executionContext)}stable-request: Unable to analyze the response returned on attempt #${currentAttempt}. Response: ${safelyStringify(res?.data, maxSerializableChars)}`);
156
+ console.error(`${formatLogContext(executionContext)}stable-request: Error message provided by your responseAnalyzer: ${safelyStringify(e.message, maxSerializableChars)}`);
157
+ performNextAttempt = true;
167
158
  }
168
159
  }
169
- }
170
- if ((!res.ok || (res.ok && performNextAttempt)) && logAllErrors) {
171
- const errorLog = {
172
- timestamp: res.timestamp,
173
- attempt: `${currentAttempt}/${maxAttempts}`,
174
- error: res?.error ??
175
- `${formatLogContext(executionContext)}stable-request: The response did not match your expectations! Response: ${safelyStringify(res?.data, maxSerializableChars)}`,
176
- isRetryable: res.isRetryable,
177
- executionTime: res.executionTime
178
- };
179
- errorLogs.push(errorLog);
180
- try {
181
- await executeWithPersistence(handleErrors, {
182
- fn,
183
- args,
184
- errorLog,
185
- maxSerializableChars,
186
- params: hookParams?.handleErrorsParams,
187
- preExecutionResult,
188
- commonBuffer,
189
- executionContext
190
- }, statePersistence, executionContext || {}, commonBuffer);
191
- }
192
- catch (e) {
193
- 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)}`);
160
+ if (circuitBreakerInstance && circuitBreakerInstance.getState().config.trackIndividualAttempts) {
161
+ if (res.ok && !performNextAttempt) {
162
+ circuitBreakerInstance.recordAttemptSuccess();
163
+ }
164
+ else if (!res.ok || performNextAttempt) {
165
+ circuitBreakerInstance.recordAttemptFailure();
166
+ if (circuitBreakerInstance.getState().state === CircuitBreakerState.OPEN) {
167
+ throw new CircuitBreakerOpenError(`${formatLogContext(executionContext)}stable-request: Circuit breaker opened after attempt ${currentAttempt}/${maxAttempts}. Blocking further retries.`);
168
+ }
169
+ }
194
170
  }
195
- }
196
- if (res.ok && !performNextAttempt) {
197
- hadAtLeastOneSuccess = true;
198
- lastSuccessfulAttemptData = res?.data;
199
- successfulAttemptsCount++;
200
- if (logAllSuccessfulAttempts) {
201
- const successfulAttemptLog = {
202
- attempt: `${currentAttempt}/${maxAttempts}`,
171
+ if ((!res.ok || (res.ok && performNextAttempt)) && logAllErrors) {
172
+ const errorLog = {
203
173
  timestamp: res.timestamp,
204
- data: res?.data,
174
+ attempt: `${currentAttempt}/${maxAttempts}`,
175
+ error: res?.error ??
176
+ `${formatLogContext(executionContext)}stable-request: The response did not match your expectations! Response: ${safelyStringify(res?.data, maxSerializableChars)}`,
177
+ isRetryable: res.isRetryable,
205
178
  executionTime: res.executionTime
206
179
  };
207
- successfulAttemptsList.push(successfulAttemptLog);
180
+ errorLogs.push(errorLog);
208
181
  try {
209
- await executeWithPersistence(handleSuccessfulAttemptData, {
182
+ await executeWithPersistence(handleErrors, {
210
183
  fn,
211
184
  args,
212
- successfulAttemptData: successfulAttemptLog,
185
+ errorLog,
213
186
  maxSerializableChars,
214
- params: hookParams?.handleSuccessfulAttemptDataParams,
187
+ params: hookParams?.handleErrorsParams,
215
188
  preExecutionResult,
216
189
  commonBuffer,
217
190
  executionContext
218
191
  }, statePersistence, executionContext || {}, commonBuffer);
219
192
  }
220
193
  catch (e) {
221
- 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)}`);
194
+ 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)}`);
222
195
  }
223
196
  }
197
+ if (res.ok && !performNextAttempt) {
198
+ hadAtLeastOneSuccess = true;
199
+ lastSuccessfulAttemptData = res?.data;
200
+ successfulAttemptsCount++;
201
+ if (logAllSuccessfulAttempts) {
202
+ const successfulAttemptLog = {
203
+ attempt: `${currentAttempt}/${maxAttempts}`,
204
+ timestamp: res.timestamp,
205
+ data: res?.data,
206
+ executionTime: res.executionTime
207
+ };
208
+ successfulAttemptsList.push(successfulAttemptLog);
209
+ try {
210
+ await executeWithPersistence(handleSuccessfulAttemptData, {
211
+ fn,
212
+ args,
213
+ successfulAttemptData: successfulAttemptLog,
214
+ maxSerializableChars,
215
+ params: hookParams?.handleSuccessfulAttemptDataParams,
216
+ preExecutionResult,
217
+ commonBuffer,
218
+ executionContext
219
+ }, statePersistence, executionContext || {}, commonBuffer);
220
+ }
221
+ catch (e) {
222
+ 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)}`);
223
+ }
224
+ }
225
+ }
226
+ if (performNextAttempt && res.isRetryable) {
227
+ res.ok = false;
228
+ }
229
+ if (attempts > 0 &&
230
+ ((!originalResOk && res.isRetryable) ||
231
+ (originalResOk && performNextAttempt) ||
232
+ performAllAttempts)) {
233
+ await delay(getNewDelayTime(retryStrategy, wait, currentAttempt, jitter), maxAllowedWait);
234
+ }
235
+ } while (attempts > 0 &&
236
+ ((res.isRetryable && !res.ok) || performAllAttempts));
237
+ if (performAllAttempts && hadAtLeastOneSuccess) {
238
+ if (trialMode.enabled) {
239
+ console.info(`${formatLogContext(executionContext)}stable-request: Final response (performAllAttempts mode):\n`, safelyStringify(lastSuccessfulAttemptData, maxSerializableChars));
240
+ }
241
+ return buildResult(true, returnResult ? lastSuccessfulAttemptData : true);
224
242
  }
225
- if (performNextAttempt && res.isRetryable) {
226
- res.ok = false;
227
- }
228
- if (attempts > 0 &&
229
- ((!originalResOk && res.isRetryable) ||
230
- (originalResOk && performNextAttempt) ||
231
- performAllAttempts)) {
232
- await delay(getNewDelayTime(retryStrategy, wait, currentAttempt, jitter), maxAllowedWait);
243
+ else if (res.ok) {
244
+ if (trialMode.enabled) {
245
+ const finalResponse = res?.data ?? lastSuccessfulAttemptData;
246
+ console.info(`${formatLogContext(executionContext)}stable-request: Final response:\n`, safelyStringify(finalResponse, maxSerializableChars));
247
+ }
248
+ return buildResult(true, returnResult ? (res?.data ?? lastSuccessfulAttemptData) : true);
233
249
  }
234
- } while (attempts > 0 &&
235
- ((res.isRetryable && !res.ok) || performAllAttempts));
236
- if (performAllAttempts && hadAtLeastOneSuccess) {
237
- if (trialMode.enabled) {
238
- console.info(`${formatLogContext(executionContext)}stable-request: Final response (performAllAttempts mode):\n`, safelyStringify(lastSuccessfulAttemptData, maxSerializableChars));
250
+ else {
251
+ throw new Error(safelyStringify({
252
+ error: res?.error,
253
+ 'Function': fn.name || 'anonymous',
254
+ 'Args': args,
255
+ }, maxSerializableChars));
239
256
  }
240
- return buildResult(true, returnResult ? lastSuccessfulAttemptData : true);
241
257
  }
242
- else if (res.ok) {
258
+ catch (e) {
243
259
  if (trialMode.enabled) {
244
- const finalResponse = res?.data ?? lastSuccessfulAttemptData;
245
- console.info(`${formatLogContext(executionContext)}stable-request: Final response:\n`, safelyStringify(finalResponse, maxSerializableChars));
260
+ console.error(`${formatLogContext(executionContext)}stable-request: Final error:\n`, e.message);
261
+ }
262
+ let errorAnalysisResult = false;
263
+ try {
264
+ errorAnalysisResult = await executeWithPersistence(finalErrorAnalyzer, {
265
+ fn,
266
+ args,
267
+ error: e,
268
+ trialMode,
269
+ params: hookParams?.finalErrorAnalyzerParams,
270
+ preExecutionResult,
271
+ commonBuffer,
272
+ executionContext
273
+ }, statePersistence, executionContext || {}, commonBuffer);
274
+ }
275
+ catch (errorAnalysisError) {
276
+ console.error(`${formatLogContext(executionContext)}stable-request: Unable to analyze the final error returned. Error message provided by your finalErrorAnalyzer: ${safelyStringify(errorAnalysisError.message, maxSerializableChars)}`);
277
+ }
278
+ if (!errorAnalysisResult) {
279
+ throw e;
280
+ }
281
+ else {
282
+ return buildResult(false, undefined, e.message || 'Function execution failed');
246
283
  }
247
- return buildResult(true, returnResult ? (res?.data ?? lastSuccessfulAttemptData) : true);
284
+ }
285
+ };
286
+ try {
287
+ if (executionTimeout && executionTimeout > 0) {
288
+ return await executeWithTimeout(executeFunction(), executionTimeout, `${formatLogContext(executionContext)}stable-request: Function execution exceeded timeout of ${executionTimeout}ms`);
248
289
  }
249
290
  else {
250
- throw new Error(safelyStringify({
251
- error: res?.error,
252
- 'Function': fn.name || 'anonymous',
253
- 'Args': args,
254
- }, maxSerializableChars));
291
+ return await executeFunction();
255
292
  }
256
293
  }
257
294
  catch (e) {
258
- if (trialMode.enabled) {
259
- console.error(`${formatLogContext(executionContext)}stable-request: Final error:\n`, e.message);
260
- }
261
- let errorAnalysisResult = false;
262
- try {
263
- errorAnalysisResult = await executeWithPersistence(finalErrorAnalyzer, {
264
- fn,
265
- args,
266
- error: e,
267
- trialMode,
268
- params: hookParams?.finalErrorAnalyzerParams,
269
- preExecutionResult,
270
- commonBuffer,
271
- executionContext
272
- }, statePersistence, executionContext || {}, commonBuffer);
273
- }
274
- catch (errorAnalysisError) {
275
- console.error(`${formatLogContext(executionContext)}stable-request: Unable to analyze the final error returned. Error message provided by your finalErrorAnalyzer: ${safelyStringify(errorAnalysisError.message, maxSerializableChars)}`);
276
- }
277
- if (!errorAnalysisResult) {
278
- throw e;
279
- }
280
- else {
281
- return buildResult(false, undefined, e.message || 'Function execution failed');
295
+ if (e instanceof TimeoutError) {
296
+ return buildResult(false, undefined, e.message);
282
297
  }
298
+ throw e;
283
299
  }
284
300
  }
285
301
  //# sourceMappingURL=stable-function.js.map