data2 / deploy /start.py
system's picture
system HF Staff
Deploy gateway e062ef52b65ba61a8a7a891b6b583130528f3164
e8aac63 verified
Raw History Blame Contribute Delete
7.04 kB
"""Supervise rootless local services for Spaces or use externally managed databases.
Signals and any unexpected child exit shut down the whole unit. No service credentials are logged.
"""
import os
import signal
import subprocess
import sys
import time
from pathlib import Path
children: list[subprocess.Popen] = []
pg_started = False
stopping = False
root = Path(os.environ.get("DATA_DIR", "/data"))
pg_bin = Path(os.environ.get("PG_BIN", "/usr/lib/postgresql/15/bin"))
pg_data = root / "postgres"
def stop(signum: int = 0, frame: object = None) -> None:
global stopping
if stopping:
return
stopping = True
for child in reversed(children):
if child.poll() is None:
child.terminate()
for child in children:
try:
child.wait(timeout=15)
except subprocess.TimeoutExpired:
child.kill()
if pg_started:
subprocess.run(
[str(pg_bin / "pg_ctl"), "-D", str(pg_data), "-m", "fast", "-w", "stop"],
check=False,
)
signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGINT, stop)
try:
if not os.environ.get("ENCRYPTION_KEYS"):
raise RuntimeError("Set ENCRYPTION_KEYS before starting the gateway.")
root.mkdir(parents=True, exist_ok=True)
if not os.environ.get("DATABASE_URL"):
if (
os.environ.get("ENVIRONMENT") == "production"
and os.environ.get("PERSISTENT_STORAGE_CONFIRMED") != "true"
):
raise RuntimeError(
"Embedded production PostgreSQL requires durable /data storage and PERSISTENT_STORAGE_CONFIRMED=true."
)
socket_dir = root / "run"
socket_dir.mkdir(exist_ok=True)
if not (pg_data / "PG_VERSION").exists():
subprocess.run(
[
str(pg_bin / "initdb"),
"-D",
str(pg_data),
"-U",
"gateway",
"--auth-local=trust",
"--auth-host=reject",
"--encoding=UTF8",
],
check=True,
)
subprocess.run(
[
str(pg_bin / "pg_ctl"),
"-D",
str(pg_data),
"-l",
str(root / "postgres.log"),
"-o",
f"-k {socket_dir} -c listen_addresses=''",
"-w",
"start",
],
check=True,
)
pg_started = True
exists = subprocess.run(
[
str(pg_bin / "psql"),
"-h",
str(socket_dir),
"-U",
"gateway",
"-d",
"postgres",
"-tAc",
"SELECT 1 FROM pg_database WHERE datname='gateway'",
],
capture_output=True,
text=True,
check=True,
)
if exists.stdout.strip() != "1":
subprocess.run(
[
str(pg_bin / "createdb"),
"-h",
str(socket_dir),
"-U",
"gateway",
"gateway",
],
check=True,
)
os.environ["DATABASE_URL"] = (
f"postgresql+asyncpg://gateway@/gateway?host={socket_dir}"
)
if not os.environ.get("REDIS_URL"):
redis_dir = root / "redis"
redis_dir.mkdir(exist_ok=True)
redis_socket = root / "redis.sock"
children.append(
subprocess.Popen(
[
"redis-server",
"--port",
"0",
"--unixsocket",
str(redis_socket),
"--unixsocketperm",
"700",
"--dir",
str(redis_dir),
"--appendonly",
"yes",
"--loglevel",
"warning",
]
)
)
os.environ["REDIS_URL"] = f"unix://{redis_socket}?db=0"
import redis
connection = redis.Redis.from_url(os.environ["REDIS_URL"])
for i in range(100):
try:
connection.ping()
break
except redis.RedisError:
time.sleep(0.1)
else:
raise RuntimeError("Embedded Redis failed to start.")
connection.close()
# Alembic serializes schema changes with a PostgreSQL advisory lock in env.py.
subprocess.run(
[
sys.executable,
"-m",
"alembic",
"-c",
"backend/alembic.ini",
"upgrade",
"head",
],
check=True,
)
# Server-only provisioning runs before the public application accepts requests.
# A password-hash seed can recreate the owner after an explicitly accepted data reset.
if os.environ.get("ADMIN_BOOTSTRAP_EMAIL"):
subprocess.run(
[
sys.executable,
"scripts/admin.py",
"bootstrap",
"--email",
os.environ["ADMIN_BOOTSTRAP_EMAIL"],
],
check=True,
)
# The web worker does not need access to the operator's provisioning secrets.
os.environ.pop("ADMIN_BOOTSTRAP_PASSWORD_HASH", None)
os.environ.pop("ADMIN_BOOTSTRAP_EMAIL", None)
api = subprocess.Popen(
[
sys.executable,
"-m",
"uvicorn",
"app.main:app",
"--host",
"0.0.0.0",
"--port",
os.environ.get("PORT", "7860"),
"--workers",
os.environ.get("WEB_CONCURRENCY", "1"),
"--limit-concurrency",
os.environ.get("MAX_CONCURRENCY", "32"),
"--timeout-keep-alive",
"5",
"--no-access-log",
"--forwarded-allow-ips",
os.environ.get("TRUSTED_PROXY_IPS", ""),
]
)
children.append(api)
while not stopping:
if any(child.poll() is not None for child in children):
raise RuntimeError("A supervised service exited unexpectedly.")
if pg_started:
result = subprocess.run(
[str(pg_bin / "pg_ctl"), "-D", str(pg_data), "status"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if result.returncode:
raise RuntimeError("Embedded PostgreSQL exited unexpectedly.")
time.sleep(1)
except Exception as exc:
# Do not include command output or database connection URLs in errors.
print(
f"Gateway startup failed ({type(exc).__name__}). Check configuration and service availability.",
file=sys.stderr,
)
stop()
sys.exit(1)
finally:
stop()