From harness-claude
Implements fallback chains for resilient services and API calls, using primary source, cache, and static defaults to ensure functional responses on failure. Includes TypeScript examples.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Provide degraded but functional responses when primary operations fail, ensuring users always get a result
Audits PHP code for fallback strategies including cache fallbacks, feature flags, default values, circuit breakers, and degraded modes to ensure graceful degradation.
Prevents cascading failures in microservices using circuit breakers with closed/open/half-open states and fallbacks. Includes opossum Node.js/TypeScript example and manual implementation for slow/unavailable dependencies.
Implements circuit breaker patterns for fault tolerance, failure detection, and fallbacks. Use for external API calls, microservices, databases, and preventing cascading failures. Includes TypeScript, Node.js, Python, Java guides.
Share bugs, ideas, or general feedback.
Provide degraded but functional responses when primary operations fail, ensuring users always get a result
// services/product-service.ts
interface Product {
id: string;
name: string;
price: number;
_fallback?: boolean;
_fallbackReason?: string;
}
interface FallbackResult<T> {
data: T;
source: 'primary' | 'cache' | 'default';
}
export async function getProduct(id: string): Promise<FallbackResult<Product>> {
// Level 1: Primary source — live API
try {
const res = await fetch(`https://api.example.com/products/${id}`, {
signal: AbortSignal.timeout(3000),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const product = await res.json();
// Refresh cache on success
await cache.set(`product:${id}`, product, { ttl: 3600 });
return { data: product, source: 'primary' };
} catch (primaryError) {
console.warn(`Primary failed for product ${id}:`, primaryError);
}
// Level 2: Cache — stale but real data
try {
const cached = await cache.get<Product>(`product:${id}`);
if (cached) {
return { data: { ...cached, _fallback: true, _fallbackReason: 'cache' }, source: 'cache' };
}
} catch (cacheError) {
console.warn(`Cache failed for product ${id}:`, cacheError);
}
// Level 3: Static default — always available
return {
data: {
id,
name: 'Product Unavailable',
price: 0,
_fallback: true,
_fallbackReason: 'default',
},
source: 'default',
};
}
// Generic fallback utility
export async function withFallback<T>(
primary: () => Promise<T>,
...fallbacks: Array<() => Promise<T> | T>
): Promise<T> {
try {
return await primary();
} catch (error) {
for (const fallback of fallbacks) {
try {
return await fallback();
} catch {
continue;
}
}
throw error; // All fallbacks failed, rethrow original
}
}
// Usage
const recommendations = await withFallback(
() => recommendationService.getPersonalized(userId),
() => recommendationService.getPopular(),
() => STATIC_RECOMMENDATIONS
);
Fallback strategies:
Marking fallback responses: Always indicate when a response is degraded. The UI can show a banner, the API can set headers, or the response object can include metadata:
// HTTP header approach
res.setHeader('X-Fallback', 'cache');
res.setHeader('X-Cache-Age', '3600');
// Response envelope approach
{ data: product, meta: { source: 'cache', staleSeconds: 3600 } }
Testing fallbacks: Inject failures in tests. Use dependency injection to swap services with failing implementations:
it('returns cached data when API is down', async () => {
mockFetch.mockRejectedValue(new Error('Network error'));
await cache.set('product:1', mockProduct);
const result = await getProduct('1');
expect(result.source).toBe('cache');
expect(result.data._fallback).toBe(true);
});
https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker#fallback