chore: sync current workspace to dev
This commit is contained in:
@@ -389,130 +389,9 @@ services:
|
||||
command:
|
||||
["/bin/sh", "-c", "/app/bin/migrate && /app/bin/supavisor eval \"$$(cat /etc/pooler/pooler.exs)\" && /app/bin/server"]
|
||||
|
||||
web:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: backend/Dockerfile
|
||||
image: social-local-backend
|
||||
container_name: social-local-web
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${SOCIAL_WEB__PORT:-8000}:8000"
|
||||
environment:
|
||||
- PYTHONPATH=/app/backend/src
|
||||
- SOCIAL_DATABASE__HOST=db
|
||||
- SOCIAL_DATABASE__PORT=5432
|
||||
- SOCIAL_DATABASE__PASSWORD=${SOCIAL_DATABASE__PASSWORD}
|
||||
- SOCIAL_REDIS__HOST=redis
|
||||
- SOCIAL_REDIS__PORT=6379
|
||||
- SOCIAL_REDIS__PASSWORD=${SOCIAL_REDIS__PASSWORD:-}
|
||||
- SOCIAL_SUPABASE__ANON_KEY=${SOCIAL_SUPABASE__ANON_KEY}
|
||||
- SOCIAL_SUPABASE__SERVICE_ROLE_KEY=${SOCIAL_SUPABASE__SERVICE_ROLE_KEY}
|
||||
- SOCIAL_SUPABASE__JWT_SECRET=${SOCIAL_SUPABASE__JWT_SECRET}
|
||||
- SOCIAL_RUNTIME__ENVIRONMENT=${SOCIAL_RUNTIME__ENVIRONMENT:-dev}
|
||||
- SOCIAL_WEB__HOST=${SOCIAL_WEB__HOST:-0.0.0.0}
|
||||
- SOCIAL_WEB__PORT=${SOCIAL_WEB__PORT:-8000}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
working_dir: /app/backend
|
||||
command: >
|
||||
sh -c "uv run gunicorn app:app --bind ${SOCIAL_WEB__HOST:-0.0.0.0}:${SOCIAL_WEB__PORT:-8000} --workers $${SOCIAL_WEB__GUNICORN__WORKERS:-2} --worker-class $${SOCIAL_WEB__GUNICORN__WORKER_CLASS:-uvicorn.workers.UvicornWorker} --timeout $${SOCIAL_WEB__GUNICORN__TIMEOUT:-60}"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
worker-critical:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: backend/Dockerfile
|
||||
image: social-local-backend
|
||||
container_name: social-local-worker-critical
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PYTHONPATH=/app/backend/src
|
||||
- SOCIAL_DATABASE__HOST=db
|
||||
- SOCIAL_DATABASE__PORT=5432
|
||||
- SOCIAL_DATABASE__PASSWORD=${SOCIAL_DATABASE__PASSWORD}
|
||||
- SOCIAL_REDIS__HOST=redis
|
||||
- SOCIAL_REDIS__PORT=6379
|
||||
- SOCIAL_REDIS__PASSWORD=${SOCIAL_REDIS__PASSWORD:-}
|
||||
- SOCIAL_SUPABASE__ANON_KEY=${SOCIAL_SUPABASE__ANON_KEY}
|
||||
- SOCIAL_SUPABASE__SERVICE_ROLE_KEY=${SOCIAL_SUPABASE__SERVICE_ROLE_KEY}
|
||||
- SOCIAL_SUPABASE__JWT_SECRET=${SOCIAL_SUPABASE__JWT_SECRET}
|
||||
- SOCIAL_RUNTIME__ENVIRONMENT=${SOCIAL_RUNTIME__ENVIRONMENT:-dev}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
working_dir: /app/backend
|
||||
command: uv run celery -A core.celery.app worker --loglevel=info --queues=critical --concurrency=2
|
||||
profiles:
|
||||
- worker
|
||||
|
||||
worker-default:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: backend/Dockerfile
|
||||
image: social-local-backend
|
||||
container_name: social-local-worker-default
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PYTHONPATH=/app/backend/src
|
||||
- SOCIAL_DATABASE__HOST=db
|
||||
- SOCIAL_DATABASE__PORT=5432
|
||||
- SOCIAL_DATABASE__PASSWORD=${SOCIAL_DATABASE__PASSWORD}
|
||||
- SOCIAL_REDIS__HOST=redis
|
||||
- SOCIAL_REDIS__PORT=6379
|
||||
- SOCIAL_REDIS__PASSWORD=${SOCIAL_REDIS__PASSWORD:-}
|
||||
- SOCIAL_SUPABASE__ANON_KEY=${SOCIAL_SUPABASE__ANON_KEY}
|
||||
- SOCIAL_SUPABASE__SERVICE_ROLE_KEY=${SOCIAL_SUPABASE__SERVICE_ROLE_KEY}
|
||||
- SOCIAL_SUPABASE__JWT_SECRET=${SOCIAL_SUPABASE__JWT_SECRET}
|
||||
- SOCIAL_RUNTIME__ENVIRONMENT=${SOCIAL_RUNTIME__ENVIRONMENT:-dev}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
working_dir: /app/backend
|
||||
command: uv run celery -A core.celery.app worker --loglevel=info --queues=default --concurrency=2
|
||||
profiles:
|
||||
- worker
|
||||
|
||||
worker-bulk:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: backend/Dockerfile
|
||||
image: social-local-backend
|
||||
container_name: social-local-worker-bulk
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PYTHONPATH=/app/backend/src
|
||||
- SOCIAL_DATABASE__HOST=db
|
||||
- SOCIAL_DATABASE__PORT=5432
|
||||
- SOCIAL_DATABASE__PASSWORD=${SOCIAL_DATABASE__PASSWORD}
|
||||
- SOCIAL_REDIS__HOST=redis
|
||||
- SOCIAL_REDIS__PORT=6379
|
||||
- SOCIAL_REDIS__PASSWORD=${SOCIAL_REDIS__PASSWORD:-}
|
||||
- SOCIAL_SUPABASE__ANON_KEY=${SOCIAL_SUPABASE__ANON_KEY}
|
||||
- SOCIAL_SUPABASE__SERVICE_ROLE_KEY=${SOCIAL_SUPABASE__SERVICE_ROLE_KEY}
|
||||
- SOCIAL_SUPABASE__JWT_SECRET=${SOCIAL_SUPABASE__JWT_SECRET}
|
||||
- SOCIAL_RUNTIME__ENVIRONMENT=${SOCIAL_RUNTIME__ENVIRONMENT:-dev}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
working_dir: /app/backend
|
||||
command: uv run celery -A core.celery.app worker --loglevel=info --queues=bulk --concurrency=1
|
||||
profiles:
|
||||
- worker
|
||||
# 开发阶段暂时禁用业务镜像(web/worker)。
|
||||
# 如需恢复,请从 git 历史恢复以下服务定义:web, worker-critical,
|
||||
# worker-default, worker-bulk。
|
||||
|
||||
init-job:
|
||||
build:
|
||||
@@ -538,6 +417,8 @@ services:
|
||||
condition: service_healthy
|
||||
working_dir: /app/backend
|
||||
command: uv run python -m core.runtime.cli bootstrap
|
||||
profiles:
|
||||
- job
|
||||
|
||||
volumes:
|
||||
redis_data:
|
||||
|
||||
Executable
+79
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
SESSION_NAME="${SESSION_NAME:-social-dev}"
|
||||
COMPOSE_FILE="$ROOT_DIR/infra/docker/docker-compose.yml"
|
||||
ENV_FILE="$ROOT_DIR/.env"
|
||||
|
||||
echo "=== Dev App Up ==="
|
||||
echo "This script assumes redis/supabase are already running via docker compose."
|
||||
echo ""
|
||||
|
||||
if ! command -v tmux >/dev/null 2>&1; then
|
||||
echo "Error: tmux is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "Error: docker is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Error: env file not found at $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$COMPOSE_FILE" ]; then
|
||||
echo "Error: compose file not found at $COMPOSE_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
. "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
echo "Error: tmux session '$SESSION_NAME' already exists." >&2
|
||||
echo "Hint: tmux kill-session -t $SESSION_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[1/2] Running bootstrap once (migrate + init-data)..."
|
||||
running_services="$(docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" ps --status running --services || true)"
|
||||
if ! printf '%s\n' "$running_services" | grep -qx "db"; then
|
||||
echo "Error: db service is not running. Start infra first." >&2
|
||||
echo "Hint: docker compose --env-file .env -f infra/docker/docker-compose.yml up -d" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! printf '%s\n' "$running_services" | grep -qx "redis"; then
|
||||
echo "Error: redis service is not running. Start infra first." >&2
|
||||
echo "Hint: docker compose --env-file .env -f infra/docker/docker-compose.yml up -d" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" --profile job run --rm init-job
|
||||
|
||||
echo "[2/2] Starting web + worker processes in tmux session '$SESSION_NAME'..."
|
||||
|
||||
WEB_CMD="cd '$ROOT_DIR' && PYTHONPATH=backend/src uv run gunicorn app:app --bind \
|
||||
${SOCIAL_WEB__HOST:-0.0.0.0}:${SOCIAL_WEB__PORT:-8000} --workers \
|
||||
${SOCIAL_WEB__GUNICORN__WORKERS:-2} --worker-class \
|
||||
${SOCIAL_WEB__GUNICORN__WORKER_CLASS:-uvicorn.workers.UvicornWorker} --timeout \
|
||||
${SOCIAL_WEB__GUNICORN__TIMEOUT:-60}"
|
||||
|
||||
WORKER_CRITICAL_CMD="cd '$ROOT_DIR' && PYTHONPATH=backend/src uv run celery -A core.celery.app worker --loglevel=info --queues=critical --concurrency=${SOCIAL_WORKER__GROUPS__CRITICAL__CONCURRENCY:-2}"
|
||||
WORKER_DEFAULT_CMD="cd '$ROOT_DIR' && PYTHONPATH=backend/src uv run celery -A core.celery.app worker --loglevel=info --queues=default --concurrency=${SOCIAL_WORKER__GROUPS__DEFAULT__CONCURRENCY:-2}"
|
||||
WORKER_BULK_CMD="cd '$ROOT_DIR' && PYTHONPATH=backend/src uv run celery -A core.celery.app worker --loglevel=info --queues=bulk --concurrency=${SOCIAL_WORKER__GROUPS__BULK__CONCURRENCY:-1}"
|
||||
|
||||
tmux new-session -d -s "$SESSION_NAME" -n web "bash -lc \"$WEB_CMD; echo '[web] exited'; exec bash\""
|
||||
tmux new-window -t "$SESSION_NAME" -n worker-critical "bash -lc \"$WORKER_CRITICAL_CMD; echo '[worker-critical] exited'; exec bash\""
|
||||
tmux new-window -t "$SESSION_NAME" -n worker-default "bash -lc \"$WORKER_DEFAULT_CMD; echo '[worker-default] exited'; exec bash\""
|
||||
tmux new-window -t "$SESSION_NAME" -n worker-bulk "bash -lc \"$WORKER_BULK_CMD; echo '[worker-bulk] exited'; exec bash\""
|
||||
|
||||
echo ""
|
||||
echo "=== Dev App Started ==="
|
||||
echo "tmux attach -t $SESSION_NAME"
|
||||
echo "tmux list-windows -t $SESSION_NAME"
|
||||
@@ -1,15 +1,43 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
COMPOSE_FILE="infra/docker/docker-compose.yml"
|
||||
ENV_FILE=".env"
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
COMPOSE_FILE="$ROOT_DIR/infra/docker/docker-compose.yml"
|
||||
ENV_FILE="$ROOT_DIR/.env"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Error: env file not found at $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$COMPOSE_FILE" ]; then
|
||||
echo "Error: compose file not found at $COMPOSE_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
required_services=(init-job web worker-critical worker-default worker-bulk redis db)
|
||||
available_services="$(docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" --profile job config --services)"
|
||||
|
||||
missing_services=()
|
||||
for service in "${required_services[@]}"; do
|
||||
if ! printf '%s\n' "$available_services" | grep -qx "$service"; then
|
||||
missing_services+=("$service")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "${#missing_services[@]}" -gt 0 ]; then
|
||||
echo "Error: runtime bootstrap gate requires services not found in compose:" >&2
|
||||
printf ' - %s\n' "${missing_services[@]}" >&2
|
||||
echo "Hint: this gate is for deployment compose that includes web/worker/init-job." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Runtime Bootstrap Gate ==="
|
||||
echo "This is the ONLY allowed entry point for deployment."
|
||||
echo ""
|
||||
|
||||
echo "[1/2] Running bootstrap (migrate + init-data)..."
|
||||
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" run --rm init-job bootstrap
|
||||
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" --profile job run --rm init-job
|
||||
|
||||
echo "[2/2] Starting web and worker services..."
|
||||
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d web worker-critical worker-default worker-bulk redis db
|
||||
|
||||
Reference in New Issue
Block a user