78 lines
3.6 KiB
Python
78 lines
3.6 KiB
Python
"""
|
|
Конфигурация Gunicorn для продакшена.
|
|
|
|
Архитектура:
|
|
- 1 воркер (workers=1) — обязательно, т.к.:
|
|
* SQLite не поддерживает несколько независимых процессов без WAL
|
|
* SSE event bus (events.py) хранит состояние в памяти одного процесса
|
|
* Notifier (poster.py) инициализируется один раз в памяти воркера
|
|
- gthread: несколько потоков внутри воркера — позволяет обслуживать
|
|
одновременно SSE-поток дашборда + вебхуки + API-запросы
|
|
- post_fork: стартует Telegram-бот и шедулер внутри воркера (не в мастере)
|
|
|
|
Локальная разработка: python intradbot.py (Flask dev server)
|
|
Продакшен (Docker): gunicorn -c gunicorn.conf.py "web.server:create_app()"
|
|
"""
|
|
|
|
import os
|
|
import threading
|
|
import time
|
|
|
|
# ── Сервер ────────────────────────────────────────────────────────────────────
|
|
|
|
bind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"
|
|
workers = 1 # строго 1 — см. комментарий выше
|
|
worker_class = "gthread" # многопоточный воркер для SSE + вебхуков одновременно
|
|
threads = 4 # потоков: SSE-клиенты + API-запросы + запас
|
|
timeout = 120 # достаточно для долгих SSE-соединений
|
|
keepalive = 5
|
|
|
|
# ── Логирование ───────────────────────────────────────────────────────────────
|
|
|
|
accesslog = "-" # stdout
|
|
errorlog = "-" # stderr
|
|
loglevel = "info"
|
|
access_log_format = '%(h)s "%(r)s" %(s)s %(b)s %(D)sµs'
|
|
|
|
# ── Хуки жизненного цикла ────────────────────────────────────────────────────
|
|
|
|
def on_starting(server):
|
|
"""Инициализация до форка воркеров (выполняется в мастер-процессе)."""
|
|
import logging
|
|
import config
|
|
import database
|
|
from intradesk import reference
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
handlers=[logging.StreamHandler()],
|
|
)
|
|
|
|
os.makedirs(os.path.dirname(config.DB_FILE), exist_ok=True)
|
|
database.init_db()
|
|
reference.seed_static()
|
|
reference.load_all()
|
|
server.log.info("Database and reference data initialized.")
|
|
|
|
|
|
def post_fork(server, worker):
|
|
"""
|
|
Выполняется в каждом воркер-процессе после fork.
|
|
Запускает Telegram-бот и шедулер как daemon-потоки внутри воркера.
|
|
"""
|
|
import schedule
|
|
from intradesk import reference
|
|
from bot.telegram import start_bot
|
|
|
|
threading.Thread(target=start_bot, daemon=True, name="telegram-bot").start()
|
|
|
|
schedule.every().monday.at("10:00").do(reference.load_all)
|
|
|
|
def _run_scheduler():
|
|
while True:
|
|
schedule.run_pending()
|
|
time.sleep(1)
|
|
|
|
threading.Thread(target=_run_scheduler, daemon=True, name="scheduler").start()
|
|
worker.log.info("Telegram bot and scheduler started in worker.")
|