[ZILANT] убрать зацикливание запроса на вебхук
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
"""Конфиг gunicorn для responder-бота.
|
||||||
|
|
||||||
|
Webhook регистрируется один раз в master (on_starting), а не в каждом worker —
|
||||||
|
иначе 4 воркера параллельно бьют setWebhook и ловят 429.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def on_starting(server):
|
||||||
|
from tg_mainbot import setup_webhook
|
||||||
|
|
||||||
|
server.log.info("gunicorn on_starting: регистрация Telegram webhook через ретранслятор")
|
||||||
|
setup_webhook()
|
||||||
|
|
||||||
|
|
||||||
|
# На случай, если webhook уже стоит, а воркеры перезапускаются — не трогаем.
|
||||||
|
# Повторная регистрация только при старте master-процесса.
|
||||||
@@ -6,7 +6,7 @@ After=network.target
|
|||||||
[Service]
|
[Service]
|
||||||
User=root
|
User=root
|
||||||
WorkingDirectory=/opt/testbot-git
|
WorkingDirectory=/opt/testbot-git
|
||||||
ExecStart=/opt/testbot-git/venv/bin/gunicorn --bind 192.168.0.109:5005 --workers 4 wsgi_bot:app
|
ExecStart=/opt/testbot-git/venv/bin/gunicorn --bind 192.168.0.109:5005 --workers 4 --config gunicorn_bot.conf.py wsgi_bot:app
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|||||||
+36
-14
@@ -1434,32 +1434,53 @@ def handle_callback(call):
|
|||||||
|
|
||||||
def setup_webhook():
|
def setup_webhook():
|
||||||
"""Настройка вебхука через ретранслятор (доставка на WEBHOOK_URL)."""
|
"""Настройка вебхука через ретранслятор (доставка на WEBHOOK_URL)."""
|
||||||
logger.info(f"starting setup_webhook")
|
logger.info("starting setup_webhook")
|
||||||
|
last_error = None
|
||||||
|
# setWebhook сам заменяет предыдущий URL; deleteWebhook не нужен и удваивает нагрузку на API.
|
||||||
|
for attempt in range(1, 6):
|
||||||
try:
|
try:
|
||||||
# Удаляем предыдущий вебхук
|
|
||||||
bot.remove_webhook()
|
|
||||||
|
|
||||||
# Устанавливаем новый вебхук:
|
|
||||||
# relay сохранит WEBHOOK_URL как адрес локальной доставки и зарегистрирует
|
|
||||||
# внешний URL на Telegram (external_relay).
|
|
||||||
bot.set_webhook(
|
bot.set_webhook(
|
||||||
url=WEBHOOK_URL,
|
url=WEBHOOK_URL,
|
||||||
secret_token=WEBHOOK_SECRET,
|
secret_token=WEBHOOK_SECRET,
|
||||||
max_connections=40
|
max_connections=40,
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"Вебхук установлен через ретранслятор {get_relay_url()}: "
|
||||||
|
f"локальная доставка {WEBHOOK_URL}"
|
||||||
)
|
)
|
||||||
logger.info(f"Вебхук установлен через ретранслятор {get_relay_url()}: локальная доставка {WEBHOOK_URL}")
|
|
||||||
logger.info(f"Секретный токен: {'установлен' if WEBHOOK_SECRET else 'не установлен'}")
|
logger.info(f"Секретный токен: {'установлен' if WEBHOOK_SECRET else 'не установлен'}")
|
||||||
logger.info(f"Прослушивание порта: {WEBHOOK_PORT}")
|
logger.info(f"Прослушивание порта: {WEBHOOK_PORT}")
|
||||||
logger.info(f"Путь вебхука: {WEBHOOK_PATH}")
|
logger.info(f"Путь вебхука: {WEBHOOK_PATH}")
|
||||||
|
|
||||||
# Логируем успешную настройку вебхука
|
|
||||||
log_event("system", "system", message=f"Вебхук установлен на {WEBHOOK_URL}")
|
log_event("system", "system", message=f"Вебхук установлен на {WEBHOOK_URL}")
|
||||||
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Ошибка настройка вебхука: {e}"
|
last_error = e
|
||||||
|
retry_after = _webhook_retry_after(e)
|
||||||
|
if retry_after is not None and attempt < 5:
|
||||||
|
logger.warning(
|
||||||
|
f"setup_webhook: попытка {attempt}/5 — {e}; ждём {retry_after} с"
|
||||||
|
)
|
||||||
|
time.sleep(retry_after)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
error_msg = f"Ошибка настройка вебхука: {last_error}"
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
log_event("error", "system", message=error_msg)
|
log_event("error", "system", message=error_msg)
|
||||||
raise RuntimeError(error_msg) from e
|
raise RuntimeError(error_msg) from last_error
|
||||||
|
|
||||||
|
|
||||||
|
def _webhook_retry_after(exc):
|
||||||
|
"""Извлекает секунды ожидания из 429 / 'retry after N', иначе None."""
|
||||||
|
text = str(exc)
|
||||||
|
if "429" not in text and "Too Many Requests" not in text and "retry after" not in text.lower():
|
||||||
|
return None
|
||||||
|
import re
|
||||||
|
match = re.search(r"retry after (\d+)", text, re.IGNORECASE)
|
||||||
|
if match:
|
||||||
|
return max(int(match.group(1)), 1) + 1
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
# Используем путь из WEBHOOK_URL
|
# Используем путь из WEBHOOK_URL
|
||||||
@app.route(WEBHOOK_PATH, methods=['POST'])
|
@app.route(WEBHOOK_PATH, methods=['POST'])
|
||||||
@@ -1474,6 +1495,7 @@ def webhook():
|
|||||||
try:
|
try:
|
||||||
update = telebot.types.Update.de_json(json_data)
|
update = telebot.types.Update.de_json(json_data)
|
||||||
bot.process_new_updates([update])
|
bot.process_new_updates([update])
|
||||||
|
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Ошибка обработки вебхука: {e}"
|
error_msg = f"Ошибка обработки вебхука: {e}"
|
||||||
|
|||||||
+6
-22
@@ -1,26 +1,10 @@
|
|||||||
import fcntl
|
from tg_mainbot import app
|
||||||
import os
|
|
||||||
|
|
||||||
from tg_mainbot import app, setup_webhook
|
# Регистрация webhook — в gunicorn_bot.conf.py (on_starting), один раз в master.
|
||||||
|
# Здесь только WSGI-приложение для воркеров.
|
||||||
|
|
||||||
def _setup_webhook_once():
|
|
||||||
"""
|
|
||||||
Регистрируем webhook один раз при старте gunicorn.
|
|
||||||
Без этого (__main__ не вызывается) Telegram не шлёт апдейты через relay —
|
|
||||||
ссылка «Подписка» (/start) молчит.
|
|
||||||
"""
|
|
||||||
lock_path = os.path.join(os.getenv("TMPDIR", "/tmp"), "zilant_webhook_setup.lock")
|
|
||||||
with open(lock_path, "w") as lock_file:
|
|
||||||
try:
|
|
||||||
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
||||||
except BlockingIOError:
|
|
||||||
# Другой воркер уже ставит webhook
|
|
||||||
return
|
|
||||||
setup_webhook()
|
|
||||||
|
|
||||||
|
|
||||||
_setup_webhook_once()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
from tg_mainbot import setup_webhook
|
||||||
|
|
||||||
|
setup_webhook()
|
||||||
app.run()
|
app.run()
|
||||||
|
|||||||
Reference in New Issue
Block a user