yggdrasil/.env.example
xfy b24cfdcabc fix(startup): replace migration panic with friendly exit + configurable retry window
DB migration failure at startup panicked via .expect() (main.rs:223),
dumping a raw backtrace for what is usually just "PostgreSQL isn't running
yet". Worse, the 1.6s runtime retry budget was reused at startup, so it
almost always failed against a cold/slow DB (docker-compose without
healthchecks, local Postgres not started, etc.).

Changes:
- pool: extract build_pg_config() (returns Result, no panic); add
  validate_database_url() so URL-format / DB_POOL_SIZE errors surface as
  friendly exit(1) instead of hitting the LazyLock's unreachable .expect()
- pool: add get_conn_for_startup() — a startup-only retry loop with a
  configurable total-duration window (MIGRATE_STARTUP_TIMEOUT_SECS,
  default 30s, 500ms interval), separate from the runtime get_conn()
  anti-avalanche fast retry (untouched)
- migrate: split run() into run_on_conn(&mut conn) so callers control the
  connection-acquisition strategy; main.rs pairs this with the startup
  retry. Advisory-lock release comment updated: exit(1) terminates the
  process just like panic, so the session-level lock is still freed
- main: startup fatal errors (bad URL, DB unreachable, migration failed)
  now each emit tracing::error! + eprintln! ERROR + targeted HINT, then
  exit(1) — no panic, no backtrace nudge
- .env.example / AGENTS.md: document MIGRATE_STARTUP_TIMEOUT_SECS

No runtime behavior change: get_conn() and its ~40 call sites are
unchanged. Advisory-lock safety preserved (documented in migrate.rs).
2026-06-22 11:24:13 +08:00

68 lines
2.9 KiB
Plaintext
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.

DATABASE_URL=postgres://postgres:postgres@localhost:5432/yggdrasil
RUST_LOG=info
# Rate Limit — 严格限流(登录、注册)
RATE_LIMIT_STRICT_PER_SEC=1
RATE_LIMIT_STRICT_BURST=5
# Rate Limit — 上传限流(图片上传)
RATE_LIMIT_UPLOAD_PER_SEC=2
RATE_LIMIT_UPLOAD_BURST=15
# Rate Limit — 图片访问限流(/uploads/*
RATE_LIMIT_IMAGE_PER_SEC=10
RATE_LIMIT_IMAGE_BURST=50
# Security
# Trusted origin for CSRF checks on write requests (POST/PUT/PATCH/DELETE).
# Set to your production origin, e.g. https://your-domain.example.
# Unset: falls back to the request Host header + X-Forwarded-Proto (behind a reverse proxy).
APP_BASE_URL=
# Set true/1/yes to add the Secure flag to the session cookie (enable in HTTPS production).
COOKIE_SECURE=false
# Number of reverse proxies in front of the app; used to extract the real client IP
# from X-Forwarded-For. 0 when serving directly; 1 behind one proxy (e.g. nginx/Caddy).
TRUSTED_PROXY_COUNT=0
# Per-query timeout in seconds; slow queries are canceled to protect the connection pool.
STATEMENT_TIMEOUT_SECS=30
# WebP encoding configuration
# Quality: 0.0 (smallest) to 100.0 (best), default 85.0
WEBP_QUALITY=85.0
# Method: 0 (fastest) to 6 (best quality), default 2
WEBP_METHOD=2
# Maximum concurrent sessions per user (default: 5, minimum: 1)
MAX_SESSIONS_PER_USER=5
# Database connection pool size (default: 20)
DB_POOL_SIZE=20
# Startup DB connection retry window in seconds (default: 30).
# How long the server waits for PostgreSQL to become reachable at startup before giving up.
# Useful when the DB starts slower than the app (docker-compose without healthchecks, cold
# local Postgres, etc.). Only affects startup; runtime connection retries are separate and
# fast-fail to avoid cascading failures.
MIGRATE_STARTUP_TIMEOUT_SECS=30
# SSR page cache duration in seconds (default: 3600).
# src/ssr_cache.rs maintains a global generation counter bumped on every post write, but
# Dioxus 0.7 does not expose an API to wire it into the incremental SSR cache key. Until such
# an API is available, this TTL is the only effective SSR cache invalidation mechanism.
SSR_CACHE_SECS=3600
# Compression algorithms for HTTP responses.
# Comma-separated list, case-insensitive. Supported: gzip, brotli (or br), deflate, zstd.
# Use "all" to enable everything (default when unset); use "none" or "off" to disable.
COMPRESSION_ALGORITHMS=gzip,brotli,deflate,zstd
# Image serving cache headers (hardcoded defaults)
# Uploaded image assets are served with Cache-Control: public, max-age=31536000, immutable.
# Processed variants (?w=, ?format=, etc.) are cached for 24 hours.
# To invalidate a cached raw upload, change its file path.
# To refresh a processed variant, change its processing parameters.
# Image disk cache limits
# Max total size in MB (default: 1024)
IMAGE_DISK_CACHE_MAX_MB=1024
# Max file age in hours before forced deletion (default: 168)
IMAGE_DISK_CACHE_MAX_AGE_HOURS=168