ADR 0054 — Reasonator deployment target: Heroku Standard-2X
Status: Accepted
Date: 2026-05-09 UTC
Refs: #1385, docs/architecture/reasonator/design.md (Decision 1), docs/architecture/reasonator/cost-model.md, ADR-0052
Context
Reasonator is a standalone FinBERT sentiment scoring service. FinBERT (ProsusAI/finbert) is ~400 MB of model weights. The service must stay warm to serve Pro+ sync requests with a p99 < 2s latency target. The operator's stated reason for extracting Reasonator from the main Raxx app is scalability.
Three deployment targets were evaluated: Heroku (Tier B per ADR-0052), AWS ECS Fargate, and AWS Lambda with provisioned concurrency.
Decision
Deploy Reasonator on a Heroku Standard-2X dyno (1 GB RAM), minimum 1 dyno always running.
Consequences
- Positive: Follows the established Tier B playbook (ADR-0052). No new infra tooling. Heroku expertise already exists in the team. Standard-2X dyno (1 GB RAM) comfortably holds FinBERT (400 MB) + Flask overhead.
- Positive: Lowest setup cost of the three options. No ALB, no ECS task definition, no IAM role wrangling.
- Negative: Heroku dyno restarts lose the in-memory model. The keep-alive cron and
--preloadflag minimize the warm-up window, but a restart incurs a 30–120 second model reload. - Negative: Heroku autoscaling is coarser than ECS — it scales on dyno count (not vCPU) and takes ~90 seconds to provision a new dyno. At the High load tier (>5k req/day), ECS is more efficient.
- Scale trigger: When daily requests exceed 5,000/day for 7 consecutive days, migrate to ECS Fargate. A Sentry alert fires at 4,000/day as the 7-day countdown.
Alternatives Considered
AWS ECS Fargate: Better at high throughput, finer-grained scaling, no dyno-restart model loss. Costs ~$96/month vs $51/month at 1k req/day. Setup requires ECS task definition, ALB, ECR pipeline, IAM roles, and VPC peering with the Heroku app. Overkill for Phase 1 load; correct choice at Phase 2+ scale. This is the designated migration path.
AWS Lambda (provisioned concurrency): Lambda cold start with a 400 MB model is 30+ seconds — disqualifying for the Pro+ sync path even with provisioned concurrency. Provisioned concurrency eliminates cold starts but costs $50/month per instance regardless of traffic, negating Lambda's pay-per-use advantage. Costs more than Heroku at every load tier for this workload. Rejected.