import Redis from "ioredis";
export const redis = new Redis(process.env.REDIS_URL ?? "redis://localhost:6379");
export interface Codec<T> {
encode(value: T): string;
decode(raw: string): T;
}
export const jsonCodec = <T>(): Codec<T> => ({
encode: (value) => JSON.stringify(value),
decode: (raw) => JSON.parse(raw) as T,
});
const inflight = new Map<string, Promise<unknown>>();
function jitteredTtl(ttlSeconds: number): number {
const spread = Math.ceil(ttlSeconds * 0.1);
return ttlSeconds + Math.floor(Math.random() * spread);
}
export async function cached<T>(
key: string,
ttlSeconds: number,
codec: Codec<T>,
producer: () => Promise<T>
): Promise<T> {
const hit = await redis.get(key);
if (hit !== null) {
return codec.decode(hit);
}
const existing = inflight.get(key) as Promise<T> | undefined;
if (existing) {
return existing;
}
const work = (async () => {
const value = await producer();
await redis.set(key, codec.encode(value), "EX", jitteredTtl(ttlSeconds));
return value;
})();
inflight.set(key, work);
try {
return await work;
} finally {
inflight.delete(key);
}
}
export async function invalidate(key: string): Promise<void> {
await redis.del(key);
}
import { Pool } from "pg";
import { cached, invalidate, jsonCodec } from "./cache";
export interface ProductDetail {
id: string;
name: string;
priceCents: number;
averageRating: number;
reviewCount: number;
}
const CACHE_VERSION = "v1";
const detailCodec = jsonCodec<ProductDetail>();
function detailKey(id: string): string {
return `product:${CACHE_VERSION}:detail:${id}`;
}
export class ProductRepository {
constructor(private readonly pool: Pool) {}
async findDetail(id: string): Promise<ProductDetail | null> {
return cached(detailKey(id), 300, jsonCodec<ProductDetail | null>(), async () => {
const { rows } = await this.pool.query(
`SELECT p.id, p.name, p.price_cents,
COALESCE(AVG(r.rating), 0) AS average_rating,
COUNT(r.id) AS review_count
FROM products p
LEFT JOIN reviews r ON r.product_id = p.id
WHERE p.id = $1
GROUP BY p.id`,
[id]
);
if (rows.length === 0) return null;
const row = rows[0];
return {
id: row.id,
name: row.name,
priceCents: row.price_cents,
averageRating: Number(row.average_rating),
reviewCount: Number(row.review_count),
};
});
}
async updatePrice(id: string, priceCents: number): Promise<void> {
await this.pool.query(`UPDATE products SET price_cents = $2 WHERE id = $1`, [id, priceCents]);
await invalidate(detailKey(id));
}
}
import { Request, Response } from "express";
import { Pool } from "pg";
import { ProductRepository } from "./ProductRepository";
const repo = new ProductRepository(new Pool());
export async function getProduct(req: Request, res: Response): Promise<void> {
const detail = await repo.findDetail(req.params.id);
if (detail === null) {
res.status(404).json({ error: "product_not_found" });
return;
}
res.json(detail);
}
export async function updateProduct(req: Request, res: Response): Promise<void> {
const priceCents = Number(req.body?.priceCents);
if (!Number.isInteger(priceCents) || priceCents < 0) {
res.status(422).json({ error: "invalid_price" });
return;
}
await repo.updatePrice(req.params.id, priceCents);
const fresh = await repo.findDetail(req.params.id);
res.json(fresh);
}
The cache-aside (lazy-loading) pattern keeps expensive computations out of the hot path by checking a fast store first and only falling back to the authoritative source on a miss. This snippet builds a small, type-safe caching layer around ioredis and wires it into an Express controller that serves an expensive product-detail read.
In cache.ts, cached is the core primitive. It serializes and deserializes values through a caller-supplied Codec so the cache stays generic while the callers stay strongly typed. On a hit it returns the parsed value; on a miss it computes the value with producer, writes it back with a jittered TTL (ttlSeconds plus a random offset), and returns it. The TTL jitter matters: if thousands of keys are written in the same second with an identical TTL, they all expire together and cause a synchronized flood of recomputation. Spreading expiry over a window smooths that out.
The more subtle problem is the cache stampede — when a popular key expires and many concurrent requests miss at once, they all run the expensive producer simultaneously. cache.ts addresses this with a per-process single-flight map (inflight): the first caller for a key stores its in-progress Promise, and later callers within the same process await that same promise instead of launching duplicate work. SETNX-style locking would be needed to coordinate across processes, but in-process coalescing removes the bulk of the duplication cheaply.
ProductRepository shows a realistic collaborator: findDetail wraps a slow join-and-aggregate query behind cache, using a versioned key (product:v1:...) so the key namespace can be bumped to invalidate everything at once. invalidate deletes a single key after a write so the next read repopulates it.
productController.ts is the thin HTTP edge. getProduct simply calls the repository and maps a null to a 404, while updateProduct writes then calls invalidate to keep the cache honest. This layering — controller, repository, cache primitive — keeps caching concerns out of both the transport and the domain query, which is exactly when this pattern is worth reaching for.
Related snips
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
module Api
module V1
class UsersController < BaseController
def show
user = User.includes(:profile).find(params[:id])
ETags for conditional requests and caching
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
use crossbeam::channel::unbounded;
use std::thread;
fn main() {
let (tx, rx) = unbounded();
Crossbeam for advanced concurrent data structures
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
Promises and async/await patterns for asynchronous JavaScript
Share this code
Here's the card — post it anywhere.