← Cloudflare Durable Objects / durable-objects / best-practices
Zpracování chyb
Jakékoli nezachycené výjimky vyvolané Durable Object nebo vyhozené infrastrukturou Durable Objects (například kvůli přetížení nebo síťovým chybám), se předají na místo volání u klienta. Zachycením těchto výjimek můžete zopakovat pokus o vytvoření DurableObjectStub a odesílání požadavků.
Chyby JavaScriptu s vlastností .retryable nastavenou na True se doporučuje opakovat, pokud jsou požadavky na Durable Object idempotentní, tedy pokud je lze aplikovat opakovaně, aniž by se změnila odpověď. Pokud požadavky idempotentní nejsou, musíte sami zvážit, co je pro vaši aplikaci nejvhodnější. Při opakování požadavků důrazně doporučujeme použít exponenciální backoff.
Chyby JavaScriptu s vlastností .overloaded nastavenou na True by se opakovat neměly. Pokud je Durable Object přetížený, opakování přetížení ještě zhorší a zvýší celkovou chybovost.
Jak jsou výjimky vyhazovány
Durable Objects mohou vyvolat výjimku dvěma způsoby:
- Výjimka může být vyvolána i v uživatelském kódu, který implementuje třídu Durable Object. Výsledná výjimka bude mít
.remotevlastnost nastavenou naTruev tomto případě. - Výjimku může vygenerovat i infrastruktura Durable Object. Mezi zdroje takových infrastrukturních výjimek patří například přechodné interní chyby, odeslání příliš mnoha požadavků na jeden Durable Object nebo příliš mnoho požadavků čekajících ve frontě kvůli pomalému či nadměrnému I/O (volání externích API nebo operace s úložištěm) uvnitř jednotlivého Durable Object. Některé infrastrukturní výjimky mohou navíc mít
.remotevlastnost nastavenou naTruenapříklad, když Durable Object překročí limity paměti nebo CPU.
Viz Řešení potíží a projděte si typy chyb, které Durable Object a/nebo infrastruktura Durable Objects vrací, a jak jim předcházet.
Příklad
Tento příklad ukazuje, jak opakovat požadavky pomocí doporučeného algoritmu exponenciálního odkladu (exponential backoff).
import { DurableObject } from "cloudflare:workers";
export interface Env {
ErrorThrowingObject: DurableObjectNamespace;
}
export default {
async fetch(request, env, ctx) {
let userId = new URL(request.url).searchParams.get("userId") || "";
// Retry behavior can be adjusted to fit your application.
let maxAttempts = 3;
let baseBackoffMs = 100;
let maxBackoffMs = 20000;
let attempt = 0;
while (true) {
// Try sending the request
try {
// Create a Durable Object stub for each attempt, because certain types of
// errors will break the Durable Object stub.
const doStub = env.ErrorThrowingObject.getByName(userId);
const resp = await doStub.fetch("http://your-do/");
return Response.json(resp);
} catch (e: any) {
if (!e.retryable) {
// Failure was not a transient internal error, so don't retry.
break;
}
}
let backoffMs = Math.min(
maxBackoffMs,
baseBackoffMs * Math.random() * Math.pow(2, attempt),
);
attempt += 1;
if (attempt >= maxAttempts) {
// Reached max attempts, so don't retry.
break;
}
await scheduler.wait(backoffMs);
}
return new Response("server error", { status: 500 });
},
} satisfies ExportedHandler<Env>;
export class ErrorThrowingObject extends DurableObject {
constructor(state: DurableObjectState, env: Env) {
super(state, env);
// Any exceptions that are raised in your constructor will also set the
// .remote property to True
throw new Error("no good");
}
async fetch(req: Request) {
// Generate an uncaught exception
// A .remote property will be added to the exception propagated to the caller
// and will be set to True
throw new Error("example error");
// We never reach this
return Response.json({});
}
}