🛡️ Resilience System
Built-in retry logic, rate limiting, and fallback mechanisms for reliable API operations.
Welcome to the Dymo API Resilience System documentation. This powerful feature ensures your applications remain stable and responsive even when facing network issues, API rate limits, or temporary service disruptions.
About the Resilience System
What is the Resilience System?
The Resilience System is a comprehensive error-handling and recovery mechanism built into all Dymo API SDKs. It provides automatic retry logic, intelligent rate limiting, and fallback data generation to ensure your applications continue functioning smoothly even under challenging conditions.
Key Features
- 🔄 Automatic Retries: Configurable retry attempts with exponential backoff
- 🚦 Rate Limiting: Intelligent tracking and management of API rate limits
- 🛡️ Fallback Data: Automatic generation of safe fallback responses when API is unavailable
- 📊 Client Tracking: Per-client rate limit tracking and management
- ⚡ Smart Error Handling: Differentiates between retry-worthy and non-retry-worthy errors
Configuration
The resilience system can be configured when instantiating any Dymo API client:
Basic Configuration
const dymo = new DymoAPI({
apiKey: "PRIVATE_TOKEN_HERE",
resilience: {
fallbackEnabled: true, // Enable fallback data generation
retryAttempts: 2, // Number of additional retry attempts
retryDelay: 1000 // Base delay in milliseconds
}
});
Configuration Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
fallbackEnabled | boolean | false | Whether to use fallback data when API fails |
retryAttempts | number | 2 | Number of additional retry attempts beyond the normal attempt (0 = no retries) |
retryDelay | number | 1000 | Base delay in milliseconds for exponential backoff |
Important: retryAttempts refers to the number of additional retries, not total attempts.
Example: retryAttempts: 2 = 1 normal attempt + 2 retries = 3 total attempts.
Usage Examples
Main SDK Usage
import DymoAPI from "dymo-api";
const dymo = new DymoAPI({
apiKey: "PRIVATE_TOKEN_HERE",
resilience: {
fallbackEnabled: true,
retryAttempts: 3,
retryDelay: 1000
}
});
// This will automatically retry on failure and use fallback if needed
try {
const result = await dymo.isValidEmail("[email protected]");
console.log("Success:", result.allow);
} catch (error) {
console.log("All attempts failed:", error.message);
}
Better Auth SDK Usage
import { betterAuth } from "better-auth";
import { dymoEmailPlugin } from "dymo-api-better-auth";
const auth = betterAuth({
plugins: [
dymoEmailPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
emailRules: { deny: ["FRAUD", "INVALID"] },
resilience: {
fallbackEnabled: true,
retryAttempts: 2,
retryDelay: 500
}
})
]
});
// The plugin will automatically handle retries and fallbacks
// when validating emails during authentication
Advanced Configuration
Exponential Backoff
The resilience system uses exponential backoff for retries. With a base delay of 1000ms and 2 retry attempts:
- Attempt 1: No delay (original request)
- Attempt 2: 1000ms delay (1000 × 2^0)
- Attempt 3: 2000ms delay (1000 × 2^1)
Total Attempts = 1 normal + N retries
Example: retryAttempts: 2 = 1 normal + 2 retries = 3 total attempts
Rate Limiting Behavior
When the API returns a 429 (Too Many Requests) status code:
- Automatic Wait: The system reads the
retry-afterheader and waits the specified time - No Retries: Rate-limited requests are not retried to avoid worsening the situation
- Client Tracking: Rate limits are tracked per client (identified by API key, rootApiKey, or "anonymous")
- Header Tracking: Monitors rate limit headers:
X-Ratelimit-Limit-Requests: Total requests per minuteX-Ratelimit-Remaining-Requests: Remaining requestsX-Ratelimit-Reset-Requests: Time until quota resetsretry-after: Wait time on 429 responses
Rate limited requests are handled separately and never count towards retry attempts. The system will wait the required time instead of retrying.
Fallback Data Generation
When fallbackEnabled: true and all retries fail, the system generates safe fallback responses:
Production Configuration
For production environments, consider these settings:
const productionConfig = {
fallbackEnabled: true, // Keep users working during outages
retryAttempts: 2, // 1 normal + 2 retries = 3 total attempts
retryDelay: 500 // Faster retries for better UX
};
Development Configuration
For development environments:
const developmentConfig = {
fallbackEnabled: false, // See actual errors during development
retryAttempts: 0, // Only normal attempt, no retries
retryDelay: 200 // Quick retries if enabled
};
No Retries Configuration
For real-time systems where retries cause delays:
const noRetriesConfig = {
fallbackEnabled: false, // Fail fast
retryAttempts: 0 // No retries, only single attempt
};
High Reliability Configuration
For critical applications needing maximum reliability:
const highReliabilityConfig = {
fallbackEnabled: true, // Always provide fallback
retryAttempts: 3, // 1 normal + 3 retries = 4 total attempts
retryDelay: 500 // Moderate retry speed
};
Monitoring and Logging
Monitor the console for resilience warnings. They provide valuable insights into:
- Network connectivity issues
- API rate limiting
- Service degradation
- Fallback data usage
Common log messages to watch for:
[WARN] [Dymo API] Client xxx is rate limited. Waiting 60 seconds...
[WARN] [Dymo API] Attempt 1 failed. Retrying in 1000ms...
[WARN] [Dymo API] Request failed after 3 attempts. Using fallback data.
[WARN] [Dymo API] Rate limited. Waiting 30 seconds (no retries)
Performance Considerations
Impact on Response Time
- First Request: Normal response time
- Retry Attempts: Add exponential backoff delays
- Rate Limit Waits: Can add significant delays (up to minutes)
- Fallback Generation: Minimal overhead (< 10ms)
Memory Usage
- Rate Limit Tracking: Stores rate limit info per client
- Client Identification: Uses
apiKey,rootApiKey, or "anonymous" as client ID - Automatic Cleanup: Expired entries removed after 5 minutes
- Minimal Overhead: < 1KB per active client
Rate Limit Headers Tracked
The system automatically tracks these headers per client:
| Header | Purpose |
|---|---|
X-Ratelimit-Limit-Requests | Total requests per minute |
X-Ratelimit-Remaining-Requests | Remaining requests in current window |
X-Ratelimit-Reset-Requests | Time until quota resets |
retry-after | Wait time for 429 responses |
Rate limit tracking is per client - each API key or unique identifier maintains its own rate limit state.
When to Disable Resilience
Consider disabling resilience in these scenarios:
- Real-time Systems: Where fallback data is unacceptable
- Critical Security: Where false positives are dangerous
- High-Performance: Where every millisecond counts
- Debugging: When you need to see actual API errors
Behavior Flow
- Check Rate Limit Status: If client is rate limited, wait for
retry-afterheader value - Make Request: Attempt the API call (Attempt 1 - normal attempt)
- Update Rate Limit Tracking: Parse and store rate limit headers for future requests
- Handle Response:
- 2xx (Success): Return response immediately
- 429 (Rate Limited): Wait for
retry-afterheader, do not retry - 5xx (Server Error): Retry with exponential backoff
- 4xx (Client Error): Do not retry, return error immediately
- Network Error: Retry with exponential backoff
- Retry Logic: For each retry attempt:
- Calculate delay:
retryDelay × 2^(attempt-1) - Wait the calculated time
- Make new request attempt
- Calculate delay:
- Fallback: If all additional retries fail and
fallbackEnabledis true, use fallback data - Final Failure: If no fallback enabled, throw the last error
Example Flow with retryAttempts: 2 and retryDelay: 1000:
• Attempt 1: Normal request (no delay)
• If fails: Wait 1000ms → Attempt 2
• If fails again: Wait 2000ms → Attempt 3
• If all fail: Use fallback or throw error
Migration Guide
From Basic Client
// Before (no resilience)
const dymo = new DymoAPI({ apiKey: "PRIVATE_TOKEN_HERE" });
// After (with resilience)
const dymo = new DymoAPI({
apiKey: "PRIVATE_TOKEN_HERE",
resilience: {
fallbackEnabled: true,
retryAttempts: 2, // 1 normal + 2 retries = 3 total attempts
retryDelay: 1000
}
});
From Custom Retry Logic
// Before (manual retry)
async function validateEmail(email) {
for (let i = 0; i < 3; i++) {
try {
return await client.isValidEmail(email);
} catch (error) {
if (i === 2) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
}
}
}
// After (built-in resilience)
async function validateEmail(email) {
return await client.isValidEmail(email); // Automatic retries and fallbacks
}
Migration from Previous Version
The retryAttempts parameter has changed in the updated version:
• Before: Total number of attempts (max 3)
• After: Number of additional retries beyond normal attempt
To maintain the same behavior:
// Previous behavior (3 total attempts max)
resilience: { retryAttempts: 2 } // Was: 1 normal + 2 retries = 3 total
// Same behavior now
resilience: { retryAttempts: 1 } // Now: 1 normal + 1 retry = 2 total
// For 3 total attempts like before
resilience: { retryAttempts: 2 } // Now: 1 normal + 2 retries = 3 total
Troubleshooting
Common Issues
Support
If you encounter issues with the resilience system:
- Check Logs: Review console warnings for clues
- Test Network: Verify internet connectivity
- Verify API Key: Ensure your key is valid and active
- Monitor Status: Check the API Status Page
- Contact Support: Reach out with your logs and configuration
When contacting support about resilience issues, please include:
- Your resilience configuration
- Relevant console logs
- Approximate time of issues
- Your API key (last 4 characters only)