Web development, performance, distributed systems, apis, databases, backend engineering — Daily Update 2026-11-01

//

//

Web Development, Performance, Distributed Systems, APIs, Databases, Backend Engineering — Daily Update 2026-11-01

Today’s Focus: Distributed Transaction Coordination Without Two-Phase Commit

The industry has spent decades treating two-phase commit (2PC) as the default answer for atomicity across service boundaries. In 2026, that default is increasingly wrong. 2PC blocks, doesn’t partition-tolerate, and couples participants to a coordinator that becomes a single point of failure. Modern architectures are converging on three practical alternatives that trade theoretical purity for operational reality.

1. Saga Pattern with Compensating Transactions

Instead of locking resources across services, a saga executes a sequence of local transactions, each with a corresponding compensating action. If step n fails, the saga runs compensations for steps n-1 down to 1. This is eventual consistency by design — no distributed locks, no coordinator bottleneck.

// Order service orchestrates
POST /orders { items, payment_id }
  → Payment service: reserve funds (compensation: release)
  → Inventory service: reserve stock (compensation: release)
  → Shipping service: create label (compensation: void)
  → Order service: confirm

The tradeoff: your application must tolerate transient intermediate states (e.g., “payment reserved, inventory pending”). Idempotency keys on every step make retries safe.

2. Event-Driven Choreography with Outbox Pattern

Services emit domain events to a local outbox table within the same transaction that mutates their own data. A relay (Debezium, custom poller) publishes events to the message bus. Consumers apply changes locally — no synchronous cross-service calls.

-- Single transaction in Order service
BEGIN;
  INSERT INTO orders ...;
  INSERT INTO outbox (event_type, payload) VALUES ('OrderCreated', '{"order_id": 123}');
COMMIT;

This guarantees at-least-once delivery. Consumers must be idempotent (dedupe via event ID). The outbox is your durability anchor — no dual-write problem.

3. Transactional Outbox + CDC for Read Model Projections

When you need strongly consistent read models (search indexes, analytics tables), pair the outbox with change-data-capture. The same relay that fans out events also streams row changes to derived stores. This keeps projections eventually consistent with bounded staleness (typically < 100ms), avoiding the read-your-writes anomaly that pure async choreography introduces.

Performance Note: Connection Pool Sizing Under Contention

If your P99 latency spikes under load, check max_connections vs. pool size. A common misconfiguration: 100 app instances × 20 pool connections = 2000 connections against a Postgres max_connections=200. The queue forms at the database, not the pool. Right-size: pool_size = (cpu_cores × 2) + effective_spindle_count, then scale instances horizontally, not pool depth.

Database Engine Observation: Postgres 17 pg_stat_io Is A Game Changer

The new pg_stat_io view exposes per-object I/O counters (reads, writes, extends, fsyncs) without pg_stat_statements overhead. Use it to identify which tables/indexes drive your write amplification before you tune checkpoint_completion_target or wal_buffers.

SELECT objname, reads, writes, extends, op_bytes
FROM pg_stat_io
WHERE backend_type = 'client backend'
ORDER BY writes DESC
LIMIT 10;

API Design Reminder: Pagination Cursors > Offset/Limit

Offset pagination scans and discards N rows per page — O(N) cost that grows linearly. Cursor-based pagination (keyset pagination) uses an index seek — O(log N). Always return next_cursor as an opaque token; never expose internal primary keys.

GET /api/v1/orders?cursor=eyJpZCI6MTIzLCJ0cyI6IjIwMjYtMTEtMDFUMDA6MDA6MDBaIn0=&limit=50

Operational Rule: Never Run ANALYZE During Peak Traffic

ANALYZE takes AccessShareLock — compatible with reads but not with CREATE INDEX CONCURRENTLY or VACUUM FULL. If autovacuum triggers analyze on a hot table during a deploy, your migration blocks. Disable per-table: ALTER TABLE orders SET (autovacuum_analyze_scale_factor = 0); and run analyze on a schedule via pg_cron.


This daily update series covers production-grade backend engineering: distributed systems patterns, database internals, API design, and operational practices. No filler — only what ships.

// THE TRANSMISSION LOG : FIELD NOTES

Weekly zero-fluff breakdowns of distributed systems, browser runtime performance, and production post-mortems delivered directly from Stella Sage.