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