Day job (Software Tech Lead, Oizom) / 2025

A cache layer that invalidates itself from database changes

Hand-written cache-aside code was serving stale reads and loading PostgreSQL. I moved caching into function wrappers and drove invalidation from database change events, so an edit from any service clears the cache.

Diagram: a write from any service hits PostgreSQL, a trigger records the change and calls pg_notify, the backend listener invalidates the matching Redis keys.
Diagram: a write from any service hits PostgreSQL, a trigger records the change and calls pg_notify, the backend listener invalidates the matching Redis keys.

Result

  • Invalidation no longer depends on every update function remembering it
  • Edits from other services, admin tools or direct SQL also clear the cache
  • Wrappers for single objects, lists and collections, schema-checked

Stack

Node.jsTypeScriptRedisPostgreSQL (triggers, pg_notify)zod@panth977/cache

Built at my day job, where I lead the software team behind the Envizom platform. The code belongs to the company; this write-up comes from my public blog post. The reusable parts are open source as @panth977/cache and @panth977/cache-redis.

The problem

The usual cache-aside pattern had the invalidation code living inside updateUser and deleteUser. A new update function could forget it. Related data (an organization, a module's expiry) needed its own invalidation. A schema change meant renaming key prefixes by hand. And an edit from another backend, a worker or a direct database change left a stale value for up to 24 hours.

What I built

  1. Caching moved into a wrapper around the function, so the read-check-set code exists once.
  2. All invalidation for an entity moved into one change handler.
  3. PostgreSQL triggers write every change into a changes table and call pg_notify; the backend listens, reads the new rows, and runs the handlers. A listened-to table records which listener handled which change, and old changes are deleted after 20 minutes.
  4. Function wrappers with zod input and output schemas, so a cached value with an old shape is not served.

Result

Cache invalidation follows the data, not the code path that changed it. A change made from another service, an admin tool or plain SQL clears the right keys. The blog post has the full SQL and code.

Read more




You have requested the PDF version of this page!
This page was not designed or optimized for your request.


You have a redirct option for your expected request:



  1. Checkout the PDF version: https://firebasestorage.googleapis.com/v0/b/panth-personal.firebasestorage.app/o/portfolio%2FPanth-Patel-Resume.pdf?alt=media



  2. Back to website: https://panth.vardayinitech.in/