Files
trumpsignal-backend/deploy
k 6876c0c280 fix: de-risk launch_seed, monitor price feeds, enforce single-process
Three pre-launch audit findings:

launch_seed.py — destructive cleanup is now OPT-IN
  Previously `launch_seed.py --yes` truncated KOL history (divergence /
  holdings / posts older than 30d) by default — an accidental run erased
  unrecoverable data, and abort_if_live_user_state() only guards on
  subscriptions/bindings, not KOL history. Now nothing is deleted unless
  --wipe is passed; the safe path is --seed-only (pure fetch). Bare/--yes
  without --wipe refuses and prints guidance.

/api/health/deep — monitor the price feeds, not just scrapers
  The deep healthcheck only watched the (redundant) Trump scrapers + DB, so a
  dead Binance/HL price feed — which silently stops ALL tp_sl_monitor stop-loss
  / take-profit firing on live trades — left health green. Added per-feed
  liveness (binance.last_tick_at, hl_price_feed.last_tick_at) with a 180s boot
  grace so startup doesn't false-503. Body now includes price_feeds[].

Single-process enforcement (multi-worker safety)
  The backend is single-process by design (in-memory scheduler, replay cache,
  tp_sl table, price_store). systemd unit lacked the --workers 1 + rationale
  that supervisor.conf already had; added it. Added a runtime advisory file
  lock (app.main._acquire_singleton_lock): only the leader starts background
  tasks; extra workers serve HTTP reads only and log CRITICAL. health/deep now
  reports is_leader so the misconfig is visible to monitors.

72 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 14:29:24 +08:00
..

Backend deployment + uptime monitoring

This folder collects the moving pieces that turn the backend from "runs on my laptop" into "runs 24/7 with auto-restart and external alerting".

What the bot needs to be reliable

  1. Auto-restart on crash — handled by systemd (Restart=always) or Docker Compose (restart: unless-stopped). Pick one.
  2. Health endpoints — exposed by app/main.py:
    • GET /api/health (shallow): 200 as long as the FastAPI process is alive. Used by Docker's internal HEALTHCHECK.
    • GET /api/health/deep: 200 only if DB ping works AND at least one Truth Social scraper has polled in the last 90s. Used by external uptime monitors.
  3. Dual-source scrapertruth_social.py (CNN archive) + trumpstruth.py (RSS). Both insert into posts with the same external_id hash, so duplicates are dropped. Whoever sees the post first wins.
  4. External uptime monitor — pings the deep health endpoint from outside the box. If we lose internet or the box is on fire, we get alerted. Recommended: UptimeRobot (free tier covers this).

docker-compose.yml is already configured with:

restart: unless-stopped
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
  interval: 15s
  timeout: 5s
  retries: 5
  start_period: 30s

Deploy steps on a fresh server:

git clone <repo>
cd backend
cp .env.example .env
# Fill in: SERVICE_USER_POSTGRES, SERVICE_PASSWORD_POSTGRES, FRONTEND_URL,
#          ENCRYPTION_KEY, AI_API_KEY, HL_MAINNET=true
docker compose up -d
docker compose logs -f api    # tail logs

To verify auto-restart works:

docker compose kill api       # simulate crash
sleep 12                      # wait for compose to relaunch
curl http://localhost:8000/api/health   # should return {"status":"ok"}

Option B — systemd (bare-metal, no Docker)

Use trumpsignal-api.service from this folder.

# 1. Code lives at /opt/trumpsignal/backend
sudo useradd -m -d /opt/trumpsignal trumpsignal
sudo -u trumpsignal git clone <repo> /opt/trumpsignal/backend
cd /opt/trumpsignal/backend
sudo -u trumpsignal python3.11 -m venv venv
sudo -u trumpsignal venv/bin/pip install -r requirements.txt

# 2. Configure
sudo -u trumpsignal cp .env.example .env
sudo -u trumpsignal nano .env       # fill in secrets

# 3. Install + start the service
sudo cp deploy/trumpsignal-api.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now trumpsignal-api

# 4. Tail logs
sudo journalctl -u trumpsignal-api -f

Test auto-restart:

sudo systemctl kill --signal=SIGKILL trumpsignal-api
sleep 12
curl http://localhost:8000/api/health   # should return {"status":"ok"}

UptimeRobot setup

  1. Sign up at https://uptimerobot.com (free tier = 50 monitors, 5-min interval).
  2. Add new monitor:
    • Type: HTTP(s)
    • URL: https://api.trump-signal.bitnews.day/api/health/deep (replace with your real domain)
    • Monitoring interval: 5 min
    • Alert contacts: add your email and/or Telegram
  3. UptimeRobot will alert you when the deep healthcheck returns 503 — i.e. when both scrapers have been silent for >90s, OR when the DB is unreachable.

Why deep, not shallow

The shallow /api/health returns 200 even if the scraper has died but the FastAPI process is still serving HTTP. A monitor pointed at the shallow endpoint would happily report "all green" while the bot silently misses posts. Always point external monitors at /api/health/deep.


Reading the deep healthcheck

{
  "status": "ok",
  "now": "2026-04-25T07:35:01.123456+00:00",
  "db_ok": true,
  "db_error": null,
  "scrapers": [
    { "name": "cnn",         "last_poll": "2026-04-25T07:34:58Z", "age_sec": 3,  "last_error": null },
    { "name": "trumpstruth", "last_poll": "2026-04-25T07:34:52Z", "age_sec": 9,  "last_error": null }
  ],
  "freshest_age_sec": 3,
  "problems": []
}

status: "degraded" + HTTP 503 means at least one item in problems is non-empty. The most common failure modes:

  • db: <error> — Postgres/SQLite can't be reached. Check DATABASE_URL.
  • scrapers: all stale (freshest=Ns) — both upstream feeds silent. Check network egress, then check if both ix.cnn.io and trumpstruth.org are responding from the box: curl -sI https://ix.cnn.io/data/truth-social/truth_archive.json

Burst-protection note (systemd)

The unit file caps restarts at 5 within 60s, so a hard misconfiguration (missing env var, etc.) stops the boot loop instead of thrashing forever. After fixing the underlying issue:

sudo systemctl reset-failed trumpsignal-api
sudo systemctl start trumpsignal-api