If you noticed occasional errors on Bacalah over the past few months — a chapter that refused to load, a login that timed out, a payment that spun and spun — this post explains what was happening and what we did about it.
The Problem: One Worker Doing Everything
Bacalah ran on a single Cloudflare Worker. One process handled everything: authentication, reading chapters, payments, community features, and scheduled tasks like sending email notifications.
Cloudflare’s free tier gives each Worker 10ms of CPU time per request. That sounds like plenty — and for simple things like serving a static page, it is. But modern web features are not simple. Verifying a login session, querying your reading history, decrypting payment data, checking watermarks — these operations stack up fast.
When traffic picked up or when a single expensive request hit the worker at the wrong moment, requests would exceed the CPU limit and Cloudflare would terminate them mid-flight. From a user’s perspective: a blank page, a spinner that never resolves, or a cryptic error message.
The worst part was how unpredictable it was. 95% of the time everything worked fine. Then suddenly it wouldn’t — and the failure pattern was impossible to predict.
The Solution: Five Specialized Workers
We restructured the entire backend into five dedicated Cloudflare Workers, each responsible for one domain:
| Worker | Responsibility |
|---|---|
| novel-auth | Login, registration, Google OAuth, session management |
| novel-core | Chapter reading, novel catalog, cover images, scheduling |
| novel-pay | Coin purchases, withdrawals, Billplz & Finverse integration |
| novel-community | Comments, KYC verification, author tools |
| novel-cron | Scheduled jobs: chapter publishing, weekly digests, reports |
Each worker gets its own CPU budget. What used to be five competing tenants on one shared allocation are now five independent processes, each sized for its actual workload.
Why This Matters for You
Faster responses. Each worker is leaner — it only loads the code it needs. The auth worker doesn’t carry payment logic. The reading worker doesn’t carry email-sending code. Smaller bundles start faster.
Failures are isolated. Before the split, if the payment service hit a CPU spike, it could slow down chapter loading. Now a payment timeout stays in novel-pay and has zero impact on novel-core. You can keep reading while the payment resolves.
Easier to scale. As Bacalah grows, we can upgrade individual workers without touching the rest. When we need more CPU for authentication (more users signing in), we upgrade just that one worker — not the entire platform.
The Numbers
After the split:
- 5 Workers deployed, each passing health checks within seconds of going live
- Zero errors during the migration — we deployed workers before routing traffic to them
- Average response time improved because bundles are 15–20% smaller per worker
What’s Next
The next step is adding custom domain routing so each worker sits behind api.bacalah.app rather than internal URLs. We’re also adding per-worker error alerting so we catch CPU spikes before users notice them.
Bacalah is still growing. The architecture you’re running on today is built to grow with it.
— The Bacalah Engineering Team
Written by
Redaksi Bacalah
Engineering Team — Bacalah