palashbera.

Writing

Things I ran into and had to work out. Mostly Rails, Postgres and background jobs, usually written up because I'd have wanted to read it six hours earlier.

RSS feed

  1. 4 min read

    Streaming an LLM response through Rails and React

    Eleven seconds of spinner became 400ms to first token with no speedup at all. Server-sent events over ActionCable, the SSE frame-splitting bug everyone ships, and the capacity arithmetic that breaks when a request holds a thread for eleven seconds.

    • Rails
    • React
    • LLM
    • Streaming
  2. 3 min read

    The infinite scroll that broke the back button

    34% of search sessions ended right after a back navigation and nobody filed a bug. The URL is the only state the browser can restore, and restoring scroll position needs the content to exist first.

    • React
    • UX
    • Routing
  3. 5 min read

    Sizing containers: threads, CPU limits, and bin-packing

    24 vCPUs at 11% utilisation, and requests still queueing. Puma workers versus threads under the GVL, the connection-pool arithmetic that autoscaling breaks, and how CFS quota throttling hides behind a healthy-looking average.

    • Docker
    • Kubernetes
    • Rails
    • Performance
  4. 4 min read

    The migration that ran fourteen hundred times

    Schema-per-tenant makes DDL O(tenants), and at 1,412 tenants a nullable boolean took fifty minutes and left the fleet half-migrated. What row-level security actually buys you, and how I'd choose now.

    • PostgreSQL
    • Multi-tenancy
    • Architecture
  5. 4 min read

    The form that dropped keystrokes

    118 controlled fields, one state object, and 70ms per character on a five-year-old laptop. Why I stopped reaching for memoisation, when uncontrolled inputs are correct, and the profiler setting that made the bug visible at all.

    • React
    • Performance
    • Forms
  6. 4 min read

    The p99 that was a lie

    The dashboard said 240ms; support had a video of eleven seconds. You cannot average percentiles, queue time is invisible from inside a request, and fan-out turns a 1% tail into one page load in five.

    • Observability
    • Performance
    • Rails
  7. 4 min read

    Idempotency keys are not optional

    Their client timed out at 30 seconds, ours completed the charge at 31. A timeout tells the caller nothing, so every mutating endpoint owes them a way to retry safely. The unique index does the arbitrating.

    • API design
    • Rails
    • Payments
  8. 3 min read

    The optimistic update that lied

    Thirty archived threads came back after a tunnel. Optimistic updates are a promise, and rollback needs a snapshot rather than a reverse operation — plus the missing fetch timeout that made every error handler unreachable.

    • React
    • State management
    • Offline
  9. 4 min read

    The cache that made it worse

    We cached a 900ms endpoint and the database hit 100% CPU for the first time. Cache stampedes scale with your traffic, stale-while-revalidate is usually the answer, and averages hide the trade you just made.

    • Redis
    • Rails
    • Performance
  10. 3 min read

    The deploy that needed two deploys

    `rename_column` runs in 8ms and breaks every container still on the previous release. Expand and contract, why removing a column is more dangerous than adding one, and the list of migrations I check before shipping.

    • Rails
    • PostgreSQL
    • Deployment
  11. 5 min read

    The cron job that ran once per container

    Scaling from one container to four sent 3,100 customers four copies of the same email. Singleton work in a multi-container deployment: dedicated schedulers, Postgres advisory locks, Kubernetes CronJobs, and why none of them are the actual fix.

    • Docker
    • Kubernetes
    • Rails
    • Distributed systems
  12. 4 min read

    Two components disagreed about the same user

    The sidebar showed the old name until reload. Eleven copies of the same database row, each fetched independently, and the distinction between client state and a cache of someone else's data.

    • React
    • State management
    • Architecture
  13. 4 min read

    The double refund

    Twenty-three orders refunded twice, found by a finance spreadsheet eleven days later. A read-modify-write race that reads as obviously correct, and why wrapping it in a transaction fixes nothing.

    • Rails
    • Concurrency
    • Payments
  14. 3 min read

    The dashboard that took twelve seconds

    Nine aggregate tiles, nine table scans. Why page caching made it a correctness argument, why counter caches couldn't help, and how one materialized view with filtered aggregates got it to 40ms.

    • PostgreSQL
    • Rails
    • Performance
  15. 2 min read

    When includes made it slower

    Fixing an N+1 dropped the query count from 501 to 2 and made the page four times slower. Why object allocation beats query count, and how `includes` silently switches between two completely different strategies.

    • Rails
    • PostgreSQL
    • Performance
← Back to home