A sidecar specialized for outbound calls — handling retries, TLS, and monitoring for network traffic the service sends out.
A service calling three downstream APIs wants retries, circuit breaking, and TLS on every one of those calls — implementing that inside the service's own code, at every call site, means the same plumbing is copy-pasted (or slightly reinvented) each time.
An ambassador is a sidecar the service's code talks to as if it were the real remote endpoint — usually over localhost. The ambassador actually makes the outbound network call, applying retries, timeouts, and TLS on the service's behalf, so the service's own code stays a simple local call.
The service calls `ambassador.get(...)` as if talking directly to the API. Retry logic lives entirely in the ambassador, reusable across every call.
class Ambassador {
async get(path, { retries = 2 } = {}) {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
return await this.#realNetworkCall(path);
} catch (err) {
if (attempt === retries) throw err;
console.log(`ambassador: retrying ${path} (attempt ${attempt + 1})`);
}
}
}
async #realNetworkCall(path) {
console.log(`ambassador: calling remote ${path} over TLS`);
if (path === "/flaky" && Math.random() < 0.5) throw new Error("timeout");
return { path, status: 200 };
}
}
// Service code stays simple — it just calls the ambassador locally.
const ambassador = new Ambassador();
const result = await ambassador.get("/flaky");
console.log(result);