Deepak Kumar Jha
Indegene — Monolith to microservices: cutting response times from 10–40s to 5–7s
Indegene Limited · Feb 2025 – Dec 2025 · Full role details →
The Problem
Indegene’s legacy platform was a monolith with a legacy React front end, slow enough under real load — 10 to 40 second responses — that it was producing recurring weekly server crashes. That is not a performance-tuning problem at that point; it is an availability problem that a straight optimisation pass on the existing architecture was unlikely to fix.
Constraints
- A legacy monolith and an outdated React front end both needed modernising, not just the slow endpoints inside them.
- The system had to keep running for existing users while the migration happened — this was a decomposition of a live system, not a rebuild of a dormant one.
- A 12–14 engineer team needed a migration plan they could execute incrementally, in a life-sciences technology environment (NASDAQ: INGN) where regulated-industry clients don’t tolerate open-ended downtime.
- A separate, high-volume batch workload (data processing jobs running close to an hour) was competing for the same server capacity as the request-serving path.
Architecture
The migration split the problem into three independent workstreams that could each ship without waiting on the others: the front end, the monolith decomposition, and the batch-processing path.
Front-end modernisation
The legacy React application was migrated to a modern architecture, decoupled from the monolith’s release cycle.
Monolith → microservices
The monolith was decomposed into services aligned to bounded contexts, so a slow or crashing code path no longer took the whole platform down with it.
Cron-based batch parallelisation
High-volume data processing jobs were parallelised across cron-scheduled workers instead of running as one long serial job competing with request traffic.
Key Decisions & Trade-offs
Decompose along failure boundaries first, feature boundaries second
The immediate business problem was recurring crashes, not slow individual features. I prioritised splitting out the services most implicated in the weekly crashes before doing a textbook-clean domain decomposition of the rest — the correct long-term service boundaries mattered less in month one than making sure one bad code path could no longer take the whole platform down.
Parallelise the batch path instead of just giving it more time
The ~60-minute batch jobs were competing with the request-serving path for the same resources. Parallelising them across cron-scheduled workers (cutting runtime to roughly 20–30 minutes) was chosen over simply moving them to off-peak hours, because off-peak scheduling doesn’t scale as data volume grows and this did.
Migrate the front end and the backend on independent timelines
Coupling the React modernisation to the microservices migration would have meant one blocked workstream stalling the other. Decoupling them let each move at the pace its own risk profile allowed — the backend decomposition was the more availability-critical of the two and got the more conservative, incremental rollout.
Outcome
- Cut API response times from 10–40 seconds to 5–7 seconds.
- Eliminated recurring weekly server crashes.
- Reduced batch-processing runtime from roughly 60 minutes to 20–30 minutes.
- Led a 12–14 engineer team through the migration.
What I'd Do Differently At Greater Scale
At greater scale, I’d introduce contract testing between the newly-split services earlier in the process — the decomposition prioritised stopping the crashes quickly, and the informal integration testing that enabled would become the bottleneck once the number of services grows past what a small team can reason about by hand.