Skip to content

Error Handling & Retry

Stock SDK includes built-in error handling and automatic retry mechanisms to help you handle unstable network conditions.

Default Behavior

SDK enables the following retry strategy by default:

OptionDefaultDescription
maxRetries3Maximum retry attempts
baseDelay1000msInitial backoff delay
maxDelay30000msMaximum backoff delay
backoffMultiplier2Backoff multiplier

Error Types That Trigger Retry

Error TypeRetry?
Request Timeout✅ Yes
Network Error (DNS/Connection)✅ Yes
HTTP 408 (Request Timeout)✅ Yes
HTTP 429 (Too Many Requests)✅ Yes
HTTP 500/502/503/504 (Server Errors)✅ Yes
HTTP 400/401/403/404 (Client Errors)❌ No

Exponential Backoff

When a request fails, SDK uses exponential backoff to calculate wait time:

delay = baseDelay × (backoffMultiplier ^ attempt)

Example (default config):

AttemptCalculationWait Time
1st1000 × 2⁰~1 second
2nd1000 × 2¹~2 seconds
3rd1000 × 2²~4 seconds

This strategy gives the server time to recover, avoiding continuous requests during overload.

Custom Retry Configuration

typescript
import { StockSDK } from 'stock-sdk';

const sdk = new StockSDK({
  timeout: 10000,
  retry: {
    maxRetries: 5,           // Max 5 retries
    baseDelay: 500,          // Initial delay 500ms
    maxDelay: 10000,         // Max delay 10 seconds
    backoffMultiplier: 1.5,  // Backoff multiplier 1.5
  }
});

Disable Retry

In some cases, you may want to disable automatic retry:

typescript
const sdk = new StockSDK({
  retry: {
    maxRetries: 0  // Disable retry
  }
});

Retry Callback

Use onRetry callback to monitor retry events for logging or debugging:

typescript
const sdk = new StockSDK({
  retry: {
    onRetry: (attempt, error, delay) => {
      console.log(`Retry attempt ${attempt}`);
      console.log(`Error: ${error.message}`);
      console.log(`Waiting ${Math.round(delay)}ms before retry...`);
    }
  }
});

Fine-grained Control

Retry Only on Specific Errors

typescript
const sdk = new StockSDK({
  retry: {
    retryOnTimeout: true,       // Retry on timeout
    retryOnNetworkError: false, // Don't retry on network error
    retryableStatusCodes: [503, 504], // Only retry on these status codes
  }
});

Provider-level Overrides

Legacy global timeout / retry / rateLimit / circuitBreaker settings still act as the default policy.
The new providerPolicies option only overrides those defaults for a specific provider, so existing initialization code remains compatible.

Typical Use Cases

  • Keep Tencent on the default rate
  • Lower the request rate only for eastmoney
  • Enable more aggressive retry or circuit breaker rules for a single provider
typescript
const sdk = new StockSDK({
  retry: {
    maxRetries: 2,
    baseDelay: 500,
  },
  rateLimit: {
    requestsPerSecond: 5,
    maxBurst: 10,
  },
  providerPolicies: {
    eastmoney: {
      timeout: 12000,
      retry: {
        maxRetries: 5,
        baseDelay: 800,
      },
      rateLimit: {
        requestsPerSecond: 3,
        maxBurst: 3,
      },
      circuitBreaker: {
        failureThreshold: 3,
        resetTimeout: 30000,
      },
    },
  },
});

Available Provider Names

  • tencent
  • eastmoney
  • sina
  • linkdiary
  • unknown

Host Fallback & Retry Budget

Some providers (e.g. eastmoney) ship with several mirror hosts. When the first host fails with a fallback-eligible error (network / timeout / 5xx, etc.), the SDK automatically switches to the next candidate host.

To avoid the maxRetries × hostCount latency blow-up, the SDK applies the following strategy:

  • First host: uses the full retry budget (default up to 4 attempts: 1 + maxRetries).
  • Subsequent fallback hosts: each is tried only once (maxRetries is forced to 0).

The total request count is therefore roughly (maxRetries + 1) + (candidateHosts - 1), which preserves disaster recovery while preventing long blocking. Unreachable hosts are also throttled by the circuit breaker and host health stats.

Error Handling

HttpError

When server returns a non-2xx status code, SDK throws HttpError:

typescript
import { StockSDK, HttpError } from 'stock-sdk';

const sdk = new StockSDK();

try {
  const quotes = await sdk.getSimpleQuotes(['invalid_code']);
} catch (error) {
  if (error instanceof HttpError) {
    console.log(`HTTP Error: ${error.status} ${error.statusText}`);
  } else {
    console.log(`Other Error: ${error.message}`);
  }
}

Timeout Error

Timeout errors appear as DOMException with name set to AbortError:

typescript
try {
  const quotes = await sdk.getSimpleQuotes(['sh000001']);
} catch (error) {
  if (error instanceof DOMException && error.name === 'AbortError') {
    console.log('Request timed out');
  }
}

Standardized Error Codes

If you want consistent error classification without losing the original TypeError / AbortError / HttpError instance, use getSdkErrorCode:

typescript
import { getSdkErrorCode, HttpError } from 'stock-sdk';

try {
  await sdk.getSimpleQuotes(['sh000001']);
} catch (error) {
  if (error instanceof HttpError) {
    console.log(`HTTP Error: ${error.status}`);
  }

  console.log(getSdkErrorCode(error));
  // Possible values: HTTP_ERROR / RATE_LIMITED / NETWORK_ERROR / TIMEOUT / CIRCUIT_OPEN ...
}

The onRetry callback still receives the original error instance with standardized metadata attached, so existing error handling stays compatible.

Configuration Reference

RetryOptions

PropertyTypeDefaultDescription
maxRetriesnumber3Maximum retry attempts
baseDelaynumber1000Initial backoff delay (ms)
maxDelaynumber30000Maximum backoff delay (ms)
backoffMultipliernumber2Backoff multiplier
retryableStatusCodesnumber[][408, 429, 500, 502, 503, 504]HTTP status codes to retry
retryOnNetworkErrorbooleantrueRetry on network errors
retryOnTimeoutbooleantrueRetry on timeout
onRetryfunction-Retry callback function

Released under the ISC License.