From global-plugin
Use when reviewing or designing code that calls a network service, handles an error, sets a timeout, implements a retry, or exposes a user-facing failure path. Do NOT use for queue-specific retry semantics (use `queue-and-retry-safety`). Covers timeouts, retry with jitter, circuit breakers, error boundaries, idempotency of external calls, graceful degradation, typed errors.
npx claudepluginhub lgerard314/global-marketplace --plugin global-pluginThis skill is limited to using the following tools:
Networks partition; tail latency dominates. Make code fail well — bounded waits, safe retries, isolated failure surfaces, typed errors. Apply whenever you touch a `fetch` call, HTTP client, SDK integration, `try/catch`, a React component that can throw, or any function returning recoverable failure.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Share bugs, ideas, or general feedback.
Networks partition; tail latency dominates. Make code fail well — bounded waits, safe retries, isolated failure surfaces, typed errors. Apply whenever you touch a fetch call, HTTP client, SDK integration, try/catch, a React component that can throw, or any function returning recoverable failure.
throw unmounts the entire tree above. Feature-level boundaries contain the blast radius and allow per-feature recovery UI.Result<T, E> for recoverable failures or a typed exception hierarchy for bugs. catch (e: unknown) always narrows before accessing properties. — Why: untyped catches hide failures; typed errors force callers to handle every outcome; narrowing prevents Cannot read properties of undefined crashes inside error handlers.void someAsyncFn() is banned. await, attach .catch with structured logging, or enqueue via a durable mechanism. — Why: unhandled promise rejections terminate newer Node runtimes; silently swallowed failures look like success to monitoring.| Thought | Reality |
|---|---|
| "I'll just retry 3 times" | Without backoff and jitter, three simultaneous retries hit the recovering service at the same instant — a thundering herd that prevents recovery. |
| "Try/catch and log it, move on" | The error is swallowed; the caller proceeds as though the operation succeeded. Data is corrupted, side effects are partial, and the symptom surfaces far from the cause. |
| "No timeout — it's usually fast" | The P99 is your 3 AM page, not the median. One slow upstream response holds a connection open for minutes and cascades into pool exhaustion. |
| "await someAsync() in a loop with no concurrency limit" | Fifty slow callers saturate the event loop. Add p-limit or a semaphore to cap in-flight requests. |
Bad — no timeout, no retry policy, untyped catch:
// BAD: no timeout, retries on all errors, swallowed failures
async function getUser(id: string): Promise<User> {
try {
const res = await fetch(`https://api.example.com/users/${id}`);
return res.json();
} catch (e) {
console.error('failed', e);
return null as any; // lie to the type system; caller assumes success
}
}
Good — AbortController timeout, typed retry with jitter, typed result:
// GOOD: bounded timeout, exponential backoff with jitter, typed Result
import { fetchWithTimeout } from './http';
import { retryWithBackoff } from './retry';
import type { Result } from './result';
type GetUserError =
| { code: 'NOT_FOUND' }
| { code: 'UPSTREAM_ERROR'; status: number }
| { code: 'NETWORK_ERROR'; cause: unknown };
async function getUser(id: string): Promise<Result<User, GetUserError>> {
return retryWithBackoff(
() => fetchWithTimeout(`https://api.example.com/users/${id}`, { timeoutMs: 5_000 }),
{ maxAttempts: 3, retryOn: isRetryableHttpError },
);
}
Bad — every call to a degraded service pays the full timeout cost:
// BAD: no circuit breaker — 10 000 req/s × 5s timeout = 50 000 concurrent requests
// waiting in the event loop when the CRM is down
async function lookupCustomerTier(customerId: string): Promise<string> {
const res = await fetch(`https://crm.internal/customers/${customerId}/tier`, {
signal: AbortSignal.timeout(5_000),
});
return res.json();
}
Good — open circuit fast-fails with a safe default; closed circuit calls normally:
// GOOD: circuit breaker; when open, returns cached/default tier in <1ms
import CircuitBreaker from 'opossum';
const crmBreaker = new CircuitBreaker(rawLookupCustomerTier, {
timeout: 5_000, // ms before a call is considered failed
errorThresholdPercentage: 50, // open after 50% failures in the rolling window
resetTimeout: 30_000, // try again after 30s
});
crmBreaker.fallback(() => 'standard'); // degrade gracefully
export async function lookupCustomerTier(customerId: string): Promise<string> {
return crmBreaker.fire(customerId);
}
Bad — one root boundary, any crash blanks the page: <ErrorBoundary fallback={<p>Something went wrong</p>}>{Header, MainContent, RecommendationPanel, Footer}</ErrorBoundary>.
Good — each independent feature wraps its own boundary so failures are isolated:
import { ErrorBoundary } from 'react-error-boundary';
function App() {
return (
<>
<Header />
<ErrorBoundary fallback={<MainContentError />}><MainContent /></ErrorBoundary>
<ErrorBoundary fallback={<RecommendationFallback />}><RecommendationPanel /></ErrorBoundary>
<Footer />
</>
);
}
For full implementation details (timeout utility, retryWithBackoff with full jitter, idempotency key patterns, opossum breaker with state events, react-error-boundary with useErrorBoundary, Result<T,E> type and typed exception hierarchy, graceful degradation patterns), see references/patterns.md.
queue-and-retry-safety (queue-level retry, at-least-once delivery); observability-first-debugging (what/how to log failures and trace them); integration-contract-safety (how upstream contracts shape retry/timeout strategy).frontend-implementation-guard (component structure); queue-and-retry-safety (DLQ, visibility timeout).One line: GREEN / YELLOW / RED. Name the reviewed surface and the overall verdict in a single sentence.
One bullet per finding: path/to/file.ts:42 — severity (blocking | concern | info) — category (timeout | retry | idempotency | circuit-breaker | error-boundary | typed-error | user-message | fire-and-forget) — what is wrong, recommended fix. Include the external call inventory (file:line, timeout yes/no, retry yes/no, idempotency key yes/no/N/A) as a table within this section.
Resilience-specific safer path for each finding. See references/review-checklist.md for the standard safer-alternative text covering unbounded retries, fail-open defaults, stringly-typed error checks, fire-and-forget promises, and at-most-once POSTs.
Mark each of the 8 Core rules PASS / CONCERN / NOT APPLICABLE with a one-line justification. See references/review-checklist.md for the full coverage table, required explicit scans, and severity definitions.
For full implementation deep-dives (timeout utility, retryWithBackoff, idempotency key patterns, opossum circuit breaker, React error boundaries, Result type, graceful degradation), see references/patterns.md. For the complete PR review checklist with coverage table, required explicit scans, and severity definitions, see references/review-checklist.md.