fix: Add DNS retry logic to Telegram bot

Problem: Python urllib3 throwing 'Failed to resolve trading-bot-v4' errors
Root cause: Transient DNS resolution failures (similar to Node.js DNS issue)

Solution: Added retry_request() wrapper with exponential backoff:
- Retries DNS/connection errors up to 3 times
- 2s → 4s → 8s delays between attempts
- Same pattern as Node.js retryOperation() in drift/client.ts

Applied to:
- /status command (position fetching)
- Manual trade execution (most critical)

User request: Configure bot to handle DNS problems better
Result: Telegram bot now self-recovers from transient DNS failures
This commit is contained in:
mindesbunister
2025-11-16 00:57:16 +01:00
parent b1ca454a6f
commit bdf1be1571

View File

@@ -4,10 +4,37 @@ Telegram Trade Bot - SECURE Command-based
Only responds to YOUR commands in YOUR chat Only responds to YOUR commands in YOUR chat
""" """
import os import os
import time
import requests import requests
from telegram import Update from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
def retry_request(func, max_retries=3, initial_delay=2):
"""
Retry wrapper for DNS/connection failures
Similar to Node.js retryOperation() logic
"""
for attempt in range(max_retries):
try:
return func()
except (requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
Exception) as e:
error_msg = str(e).lower()
# Check for transient DNS/connection errors
if 'name or service not known' in error_msg or \
'failed to resolve' in error_msg or \
'connection' in error_msg:
if attempt < max_retries - 1:
delay = initial_delay * (2 ** attempt)
print(f"⏳ DNS/connection error (attempt {attempt + 1}/{max_retries}): {e}", flush=True)
print(f" Retrying in {delay}s...", flush=True)
time.sleep(delay)
continue
# Non-transient error or max retries reached
raise
raise Exception(f"Max retries ({max_retries}) exceeded")
# Configuration # Configuration
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN') TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
N8N_WEBHOOK_URL = os.getenv('N8N_WEBHOOK_URL') N8N_WEBHOOK_URL = os.getenv('N8N_WEBHOOK_URL')
@@ -58,12 +85,12 @@ async def status_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
print(f"📊 /status command received", flush=True) print(f"📊 /status command received", flush=True)
try: try:
# Fetch positions from trading bot API # Fetch positions from trading bot API with retry logic
response = requests.get( response = retry_request(lambda: requests.get(
f"{TRADING_BOT_URL}/api/trading/positions", f"{TRADING_BOT_URL}/api/trading/positions",
headers={'Authorization': f'Bearer {API_SECRET_KEY}'}, headers={'Authorization': f'Bearer {API_SECRET_KEY}'},
timeout=10 timeout=10
) ))
print(f"📥 API Response: {response.status_code}", flush=True) print(f"📥 API Response: {response.status_code}", flush=True)
@@ -646,12 +673,12 @@ async def manual_trade_handler(update: Update, context: ContextTypes.DEFAULT_TYP
try: try:
print(f"🚀 Manual trade: {direction.upper()} {symbol_info['label']}{' (FORCED)' if force_trade else ''}", flush=True) print(f"🚀 Manual trade: {direction.upper()} {symbol_info['label']}{' (FORCED)' if force_trade else ''}", flush=True)
response = requests.post( response = retry_request(lambda: requests.post(
f"{TRADING_BOT_URL}/api/trading/execute", f"{TRADING_BOT_URL}/api/trading/execute",
headers={'Authorization': f'Bearer {API_SECRET_KEY}'}, headers={'Authorization': f'Bearer {API_SECRET_KEY}'},
json=payload, json=payload,
timeout=60, timeout=60,
) ))
print(f"📥 Manual trade response: {response.status_code}", flush=True) print(f"📥 Manual trade response: {response.status_code}", flush=True)