8f016f25df
- ORM migration: models/ops 重构 - deploy: 标准化 systemd timer/service 部署体系 - MCP server: 5 个只读工具(任务/状态/数据集) - daily check: 数据一致性巡检 - watch: task_watch 后台监控 - kline_daily: 麦蕊优先,时间门禁15:00 - 删除: task_industry_sector, task_sector_features
78 lines
2.4 KiB
Bash
Executable File
78 lines
2.4 KiB
Bash
Executable File
#!/bin/sh
|
||
# service_run.sh — Docker 入口
|
||
#
|
||
# 单进程跑:FastAPI dashboard(uvicorn)+ 进程内 scheduler(worker)
|
||
# 用 uvicorn 主进程 + 一个 daemon thread 跑 worker 的 scheduler 循环。
|
||
#
|
||
# 设计原因:docker-compose 一容器一服务最简单,systemd timer 的事交给
|
||
# 进程内 scheduler(避免 docker 里跑 systemd)。原来 .env 里的 schedule
|
||
# 表就是为这个准备的。
|
||
|
||
set -eu
|
||
|
||
RUNTIME_MODE="${RUNTIME_MODE:-docker}"
|
||
|
||
if [ "$RUNTIME_MODE" != "docker" ]; then
|
||
echo "[service] ❌ ERROR: service_run.sh 是 Docker 入口,只在 RUNTIME_MODE=docker 时可用。" >&2
|
||
echo "[service] 当前 RUNTIME_MODE=$RUNTIME_MODE" >&2
|
||
echo "[service] Linux 宿主机部署请使用 systemd timer/service,不要运行此脚本。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 等 PG 就绪(避免 race:market_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 |