fix: replace EasyOCR subprocess with persistent microservice (eliminates 30-60s cold start) - #268
Conversation
…nate 30-60s cold start Every OCR request previously spawned a fresh Python process that reloaded PyTorch + EasyOCR from scratch (30-60s), then discarded the model on exit. The 60s timeout in evaluation.ts existed specifically for this cold start. This replaces that pattern with a FastAPI microservice (ocr_server.py) that loads EasyOCR once at startup via uvicorn lifespan, then handles every subsequent request against the warm reader (~500ms instead of 30-60s). Changes: - ai-services/ocr_server.py: new FastAPI server wrapping the existing easyocr_evaluator.run_fast_ocr() pipeline — no logic changes, just a persistent process boundary instead of a per-request subprocess - backend/src/routes/evaluation.ts: both execFileSync OCR calls replaced with fetch() to http://127.0.0.1:8001/ocr; timeout reduced 60s → 15s - backend/src/config.ts: OCR_SERVICE_URL constant (env-overridable) - ai-services/requirements.txt: add fastapi, uvicorn - ai-services/scripts/easyocr_evaluator.py: broaden paddle import guard from except ImportError to except Exception (covers binary-compat errors) - ecosystem.config.js: pm2 config for both fln-backend and fln-ocr - ai-services/scripts/test_ocr_server.py: integration test — starts server, verifies health + OCR shape + sub-10s warm inference, 4/4 passed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
b42d719 to
59d578b
Compare
|
Hey @tanvishdesai , this looks good overall. The microservice approach and the performance improvements seem to solve the cold-start issue well. I just have one deployment-related request before we merge this. Our production server runs the other services using systemd, not PM2. We moved away from PM2 so that services automatically restart if they crash. Could you please replace ecosystem.config.js with a systemd service file for fln-ocr, following the same setup as our existing services? Please use: Type=simple I can share one of our existing systemd unit files if you need a reference. One more small thing. Please add a note in the PR description that evaluation.ts now connects to the OCR service at 127.0.0.1:8001. This means the OCR service should be running before the main backend starts receiving actual traffic. This is not a blocker because, if the OCR service is down, the backend should return an error instead of crashing. However, it would be good to mention this for deployment and restart purposes. Everything else, including the FastAPI implementation, tests, and configuration changes, looks good to me. |
Production uses systemd, not PM2. Adds fln-ocr.service with Restart=on-failure / RestartSec=3 and logs to /var/log/tenali/, matching the pattern of existing services on the droplet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for pointing it out @jgupta05072003-code, have updated it. Replaced with using exactly the config you mentioned (, , , logs to ). Also deleted the PM2 file entirely since it's not used. Added the startup dependency note in the PR description as well — basically just explains that if the OCR service is down, the backend returns a 502 instead of crashing, and that should be up before traffic hits . Let me know if the service file needs any adjustments for your existing setup (like a different deploy user or path)! |
Problem
Every OCR scan submission spawned a fresh Python process that reloaded PyTorch + EasyOCR from scratch. Cold-start cost: 30–60 seconds per request. The
timeout: 60000inevaluation.tsexisted specifically for this. Two simultaneous uploads = two full model loads competing for ~1.5GB RAM each → OOM risk on a 2GB droplet.Solution
Replace the per-request subprocess with a persistent FastAPI microservice (
ai-services/ocr_server.py) that loads EasyOCR once at startup via uvicorn's lifespan hook. Every subsequent request hits a warm reader.Changes
ai-services/ocr_server.py— new FastAPI server wrapping the existingeasyocr_evaluator.run_fast_ocr()pipeline. No logic changes — same blue-pen filter, same component detection, same EasyOCR allowlist.backend/src/routes/evaluation.ts— bothexecFileSyncOCR calls replaced withfetch()tohttp://127.0.0.1:8001/ocr. Timeout reduced from 60s → 15s.backend/src/config.ts—OCR_SERVICE_URLconstant, overridable via env.ai-services/requirements.txt— addfastapi,uvicorn.ai-services/scripts/easyocr_evaluator.py— broaden paddle import guard fromexcept ImportErrortoexcept Exception(covers binary-compatibility errors from the numpy ABI).fln-ocr.service— systemd unit for the OCR microservice (replacesecosystem.config.js). Logs to/var/log/tenali/. Deploy viasudo cp fln-ocr.service /etc/systemd/system/ && sudo systemctl enable --now fln-ocr.ai-services/scripts/test_ocr_server.py— integration test that starts the server, waits for EasyOCR to warm, then verifies health + OCR response shape + sub-10s warm inference.Test results
Deployment (one-time on droplet)
🤖 Generated with Claude Code