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:
@@ -4,10 +4,37 @@ Telegram Trade Bot - SECURE Command-based
|
||||
Only responds to YOUR commands in YOUR chat
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
import requests
|
||||
from telegram import Update
|
||||
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
|
||||
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
|
||||
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)
|
||||
|
||||
try:
|
||||
# Fetch positions from trading bot API
|
||||
response = requests.get(
|
||||
# Fetch positions from trading bot API with retry logic
|
||||
response = retry_request(lambda: requests.get(
|
||||
f"{TRADING_BOT_URL}/api/trading/positions",
|
||||
headers={'Authorization': f'Bearer {API_SECRET_KEY}'},
|
||||
timeout=10
|
||||
)
|
||||
))
|
||||
|
||||
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:
|
||||
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",
|
||||
headers={'Authorization': f'Bearer {API_SECRET_KEY}'},
|
||||
json=payload,
|
||||
timeout=60,
|
||||
)
|
||||
))
|
||||
|
||||
print(f"📥 Manual trade response: {response.status_code}", flush=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user