3c9ce72b51
Docker Image CI / build (push) Waiting to run
Media downloads jammed process-wide: Kurigram serializes them through a single get_file slot (max_concurrent_transmissions=1), and a zombie media-DC connection (upload.GetFile timing out) held that slot forever. The main-DC watchdog (get_me) never noticed, and the 60s cache sweep kept re-queuing the failing file, so all feed images turned into broken placeholders. - telegram_client: count consecutive download timeouts; after N (default 5) reuse _restart_client() to rebuild the media connection — the only recovery signal the main-DC watchdog cannot provide. Any success resets the streak. - telegram_client/config: set max_concurrent_transmissions (default 3) so one hung download is no longer an instant total outage (blast-radius limiter only). - api_server: negative-cache with exponential backoff for repeatedly-failing files (skip in background sweep, fast 503+Retry-After in get_media, record/clear in the dedup runner and background worker; FloodWait excluded). - dockercompose/tests: document TG_MAX_CONCURRENT_TRANSMISSIONS and MEDIA_TIMEOUT_RESTART_THRESHOLD; update mock config; add self-heal/backoff tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
70 lines
4.2 KiB
YAML
70 lines
4.2 KiB
YAML
volumes:
|
|
pyrogram_bridge:
|
|
|
|
services:
|
|
pyrogram_bridge:
|
|
image: ghcr.io/vvzvlad/pyrogram-bridge:latest
|
|
container_name: pyrogram-bridge
|
|
environment:
|
|
TG_API_ID: XXX
|
|
TG_API_HASH: XXX
|
|
# TG_PROXY_HOST: 10.0.0.1 # MTProto proxy host (SOCKS5). Prefer a literal IP over a hostname:
|
|
# # a hostname is re-resolved on every reconnect, so flaky DNS during a
|
|
# # network blip can wedge Pyrogram's reconnect.
|
|
# TG_PROXY_PORT: 1080 # MTProto proxy SOCKS5 port (default: 1080)
|
|
# TG_PROXY_USERNAME: XXX # SOCKS5 username (optional)
|
|
# TG_PROXY_PASSWORD: XXX # SOCKS5 password (optional)
|
|
# TG_WATCHDOG_ENABLED: "True" # Active liveness watchdog: detects 'zombie' sessions and restarts in-process (default: True)
|
|
# TG_WATCHDOG_INTERVAL: 60 # Seconds between liveness probes (default: 60)
|
|
# TG_WATCHDOG_TIMEOUT: 10 # Seconds to wait for each get_me probe (default: 10)
|
|
# TG_WATCHDOG_FAILURES: 3 # Consecutive failed probes before restart (default: 3)
|
|
# TG_WATCHDOG_HEARTBEAT_EVERY: 30 # Emit an INFO watchdog heartbeat every N successful probes (default: 30)
|
|
# TG_DISCONNECT_FLAP_LIMIT: 3 # Disconnect events within the flap window before an in-process restart (default: 3)
|
|
# TG_DISCONNECT_FLAP_WINDOW: 120 # Flap detection window in seconds (default: 120)
|
|
# TG_CHAT_CACHE_TTL_HOURS: 12 # TTL for cached channel info (title/username/id); removes GetFullChannel from the poll hot path (default: 12)
|
|
# TG_RPC_CONCURRENCY: 1 # Max concurrent live Telegram RPC calls — global throttle (default: 1)
|
|
# TG_RPC_MIN_INTERVAL_MS: 500 # Minimum gap between live Telegram RPC starts, ms (default: 500)
|
|
# TG_RPC_TIMEOUT: 60 # Max seconds a single live Telegram RPC may run before timing out (default: 60)
|
|
# MEDIA_DOWNLOAD_TIMEOUT_MIN: 120 # Min per-download timeout, seconds — also the timeout for regular (non-large) files (default: 120)
|
|
# MEDIA_DOWNLOAD_TIMEOUT_MAX: 1800 # Max per-download timeout, seconds — cap for the largest videos (default: 1800)
|
|
# MEDIA_DOWNLOAD_MIN_SPEED: 262144 # Assumed floor download speed, bytes/s — large-video timeout ≈ file_size / this, clamped to [MIN,MAX] (default: 262144 = 256 KB/s)
|
|
# IO_THREAD_POOL_SIZE: 32 # Size of the asyncio default threadpool for blocking I/O (SQLite/python-magic/pickle/os.walk); raise on a busy 1-2 CPU box (default: 32)
|
|
# TG_MAX_CONCURRENT_TRANSMISSIONS: 3 # Max concurrent Telegram file transmissions (Pyrogram get_file semaphore). Kurigram default is 1, so one hung download blocks ALL media (default: 3)
|
|
# MEDIA_TIMEOUT_RESTART_THRESHOLD: 5 # Consecutive media-download timeouts before an in-process restart rebuilds the zombie media-DC connection (the main-DC watchdog can't see this) (default: 5)
|
|
PYROGRAM_BRIDGE_URL: https://pgbridge.example.com
|
|
API_PORT: 80
|
|
TOKEN: ХХХ
|
|
TIME_BASED_MERGE: True
|
|
SHOW_BRIDGE_LINK: True
|
|
SHOW_POST_FLAGS: True
|
|
TZ: Europe/Moscow
|
|
restart: always
|
|
volumes:
|
|
- pyrogram_bridge:/app/data
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-file: 5
|
|
max-size: 10m
|
|
labels:
|
|
traefik.enable: "true"
|
|
traefik.http.routers.pgbridge.rule: Host(`pgbridge.example.com`)
|
|
traefik.http.services.pgbridge.loadBalancer.server.port: 80
|
|
traefik.http.routers.pgbridge.entrypoints: websecure
|
|
traefik.http.routers.pgbridge.tls: true
|
|
com.centurylinklabs.watchtower.enable: "true"
|
|
autoheal: true
|
|
healthcheck:
|
|
# Lightweight process/loop liveness probe. /ping never touches Telegram or the
|
|
# filesystem, so it answers instantly even while a TG RPC is hung — unlike the old
|
|
# /rss?limit=1 check, which could exceed the 5s timeout on a cold cache and get the
|
|
# container restarted mid-download (corrupted temp files). TG liveness is now judged
|
|
# by the in-process watchdog, which /ping reports via its last-probe age.
|
|
test: ["CMD", "curl", "-sf", "http://127.0.0.1:80/ping"]
|
|
interval: 5m
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 30s
|
|
start_interval: 5s
|
|
|