A performance-marketing company runs its campaigns through an ad platform we built: two Django systems that redirect and track every click across more than a dozen domains. As traffic grew, the platform began crashing every few days, worst during the highest-load campaigns. We modernized the infrastructure around the application, not the application itself, and migrated it to managed cloud. It has run at near-zero incidents since, serving millions of requests a month. We name the metrics, not the client.
The Situation
Our client operates in performance marketing: affiliate campaigns whose every click is money, routed through a platform of two Django systems. One serves the public campaign links across more than a dozen domains; the other validates and records each click, running campaign checks, geo rules, click and lead caps, per-IP rate limits, and link rotation before anything gets counted. When this platform is down, campaigns keep spending while the clicks that justify the spend go unrecorded.
The platform had been built years earlier, for the traffic it had then, and the application code was doing its job. The environment underneath was the problem: a single bare-metal server, a self-managed database on the same box, storage backing up, deployments done by hand, and no observability to see any of it coming. As campaign traffic grew, the system began crashing every few days, and the crashes clustered exactly where they cost the most: during the highest-load campaigns.
What We Did
Two goals, set with the client: improve product stability, and make the stack modern, secure and maintainable. A rewrite was never on the table; the application logic had proven itself for years. The scope was everything around it.
We containerized both applications with Docker and moved the operation to cloud infrastructure: a managed PostgreSQL database with automated backups, a dedicated web server with reserved networking, and deployments automated from the repository instead of run by hand. We integrated observability, monitoring and error tracking (DataDog, Sentry), with alerts on the failure modes that used to be invisible: resource exhaustion, disk filling up, application errors. And we wrote the operational documentation, an infrastructure map and runbooks for deploys, restarts, and log review, so the platform’s operation no longer lived in anyone’s head.
The migration itself: DNS TTLs lowered a day ahead, the database copied to the managed instance, traffic switched, the old server retired.
A year later we returned for a database performance pass, because reporting at this scale is a balancing act: every index that speeds up a real-time report slows down the writes underneath it, and this platform writes on every click. We adjusted the data structures and applied indexing incrementally, measuring at every step which changes were hurting database writes in our case, and settled where the compromise holds: reports close to real time, on a database that still keeps up with the click stream. The reporting queries themselves were rewritten to cut the load the daily reports put on the database.
The relationship has continued since: we maintain the platform and have augmented the client’s team on other supporting initiatives.
What Moved
Stability first, because it was the goal that triggered the work. Before the modernization, crashes every few days under campaign load. Since, near-zero incidents: the platform runs unattended for months at a time, at a load average around five percent of its capacity.
Then the scale that stability holds up under. Measured from 20 months of production access logs: 5 to 6 million requests a month on average, 9.8 million in the peak month, peak days around 640,000 requests, roughly 2 million tracked clicks a month. Seasonal campaign peaks run at several times the quiet months, and the platform absorbs them without any scaling work. All of these figures are measured by us from production logs.
Where It Went
The codebase that was crashing is the same codebase serving the peaks now. What changed is everything around it: the platform under the software, the automation around releases, and the visibility that turns surprises into alerts. When a working system outgrows its infrastructure, that is the honest scope of the fix: modernize the platform under it, and leave proven software alone.