Files
market_sync/bin/service_run.sh
T
gao fbc3cc84f0 feat(service): dockerize — Dockerfile + docker-compose + 统一入口
把项目打包成可部署的数据同步服务:

- Dockerfile (multi-stage builder/runtime, slim base, 含 healthcheck)
- docker-compose.yml (postgres:16-alpine + market_sync, 持久化 pgdata + logs)
- .dockerignore (减 build context)
- bin/service_run.sh (单进程跑 uvicorn + scheduler 线程)
- app/entrypoints/worker.py 抽 start_scheduler_thread() (幂等)

部署:
  docker compose up -d
  # 然后访问 http://localhost:8100/docs 看 FastAPI

设计选择:
  - 单容器一服务(uvicorn 主 + scheduler daemon thread),不用 supervisord
  - 原 systemd timer 由进程内 scheduler 取代(配置已存在于 config 表)
  - PG 用 docker volume 持久化;同步日志单独 volume
2026-07-07 16:30:56 +08:00

69 lines
2.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# service_run.sh — Docker 入口
#
# 单进程跑:FastAPI dashboarduvicorn+ 进程内 schedulerworker
# 用 uvicorn 主进程 + 一个 daemon thread 跑 worker 的 scheduler 循环。
#
# 设计原因:docker-compose 一容器一服务最简单,systemd timer 的事交给
# 进程内 scheduler(避免 docker 里跑 systemd)。原来 .env 里的 schedule
# 表就是为这个准备的。
set -eu
# 等 PG 就绪(避免 racemarket_sync 比 postgres 早启)
if [ -n "${PG_HOST:-}" ]; then
echo "[service] wait for PG ${PG_HOST}:${PG_PORT:-5432}..."
for i in $(seq 1 30); do
if python -c "
import socket, sys
s = socket.socket()
s.settimeout(2)
try:
s.connect(('${PG_HOST}', ${PG_PORT:-5432}))
print('pg ready')
except Exception as e:
sys.exit(1)
" >/dev/null 2>&1; then
echo "[service] PG up after ${i}s"
break
fi
sleep 1
done
fi
# seed datasource + sync registry + schedule(幂等)
python -c "
from app.core.datasource.registry import build_default_registry, seed_datasource_configs
from app.core.sync.registry import seed_sync_registry, recover_interrupted_syncs
from app.core.scheduler.scheduler import seed_schedule_configs
build_default_registry()
seed_datasource_configs()
seed_sync_registry()
recover_interrupted_syncs()
seed_schedule_configs()
print('[service] seed 完成')
"
# 后台启动 scheduler(独立线程)
python -c "
from app.entrypoints.worker import start_scheduler_thread
start_scheduler_thread()
print('[service] scheduler thread started')
import time
while True:
time.sleep(60)
" &
SCHEDULER_PID=$!
# trap SIGTERM 优雅退出
trap "echo '[service] stopping scheduler'; kill ${SCHEDULER_PID} 2>/dev/null || true; wait" TERM INT
# 前台跑 uvicorn(主进程)
echo "[service] starting uvicorn on ${API_HOST:-0.0.0.0}:${API_PORT:-8100}"
exec uvicorn app.api.main:app \
--host "${API_HOST:-0.0.0.0}" \
--port "${API_PORT:-8100}" \
--workers 1 \
--log-level "${LOG_LEVEL:-info}" \
--no-access-log