Hands
Hands let a human change the world: pick something up, write, pay. A microservice's hands are its outbound integrations — calls to other services, third-party APIs (payment gateways, SMS providers, LLM APIs) and AWS services. Hands are powerful and dangerous: the outside world can be slow, broken or expensive.
What hands typically do
| Action | Example |
|---|---|
| Call another internal service | The Cashier asks the Waiter for the order total |
| Call a third-party API | Charge a card via a payment provider; send an SMS |
| Call an AI model | Summarise customer feedback |
| Use AWS services | Store a receipt PDF in S3 |
Five rules for safe hands
1. Always use a timeout
Never wait forever. If the payment provider usually answers in 300 ms, a 3-second timeout is generous. Without one, a slow partner keeps your human (and your bill) running until Lambda's own timeout.
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 3000);
try {
const res = await fetch(`${process.env.PAYMENTS_URL}/charges`, {
method: "POST",
headers: { "Content-Type": "application/json", "Idempotency-Key": orderId },
body: JSON.stringify({ amount, currency: "INR" }),
signal: controller.signal,
});
if (!res.ok) throw new Error(`Payment failed: ${res.status}`);
return await res.json();
} finally {
clearTimeout(timer);
}
2. Retry carefully, with backoff
Temporary failures are normal. Retry a few times with exponential backoff and jitter (wait 200 ms, 400 ms, 800 ms… plus randomness) — but only for errors that might succeed next time, and only for operations that are idempotent (notice the Idempotency-Key header above: the provider won't charge twice).
If the work came from an SQS queue, the simplest retry is to let the message fail and return to the queue; after a few attempts it moves to a dead-letter queue for investigation.
3. Don't keep hitting a broken thing
If a partner is down, hammering it makes everything worse. A circuit breaker stops calls for a while after repeated failures, then tries again carefully. In serverless designs, queues plus dead-letter queues and Step Functions retries often give the same protection with less code.
4. Keep the keys in your pocket, not your hand
API keys and passwords belong in Secrets Manager (or Parameter Store), fetched at runtime and cached briefly — never hard-coded or committed to Git.
5. Prefer letters for slow or risky work
If an action is slow or might fail, don't do it while a customer waits. Put a message in a queue, acknowledge the customer, and let a worker's hands do it in the background.
Hands that call other humans
When one service calls another synchronously, it creates a dependency. Prefer:
- Events over direct calls where possible ("tell, don't ask").
- A local copy of data you need often, kept fresh by events, instead of asking every time.
- Fallbacks — if the recommendation service is down, show popular items instead of failing the page.
Hands should be gentle with the world: time out, retry only what's safe, back off when others are struggling, and never carry secrets openly.