Запуск в production: Docker, systemd, supervisord, мониторинг, обновление зависимостей.
Ключевая идея: Production-развёртывание требует надёжного управления процессами, логирования, мониторинга и безопасного хранения сессионных данных.
Перед деплоем убедитесь:
import os
from telethon import TelegramClient
from telethon.sessions import StringSession
# Безопасная конфигурация
api_id = int(os.environ['TELETHON_API_ID'])
api_hash = os.environ['TELETHON_API_HASH']
session_string = os.environ['TELETHON_SESSION']
client = TelegramClient(
StringSession(session_string),
api_id,
api_hash
)FROM python:3.11-slim
WORKDIR /app
# Установка зависимостей
COPY pyproject.toml poetry.lock ./
RUN pip install poetry && poetry install --no-dev --no-interaction
# Копирование кода
COPY . .
# Запуск
CMD ["poetry", "run", "python", "main.py"]version: '3.8'
services:
telethon-app:
build: .
environment:
- TELETHON_API_ID=${TELETHON_API_ID}
- TELETHON_API_HASH=${TELETHON_API_HASH}
- TELETHON_SESSION=${TELETHON_SESSION}
restart: unless-stopped
volumes:
- ./logs:/app/logsКлючевая идея: Docker обеспечивает воспроизводимую среду. Переменные окружения передаются через .env файл, который не хранится в репозитории.
TELETHON_API_ID=123456
TELETHON_API_HASH=abc123def456
TELETHON_SESSION=1ApWapzMBu4s...Для запуска на сервере без Docker:
[Unit]
Description=Telethon Userbot
After=network.target
[Service]
Type=simple
User=telethon
WorkingDirectory=/opt/telethon
Environment=TELETHON_API_ID=123456
Environment=TELETHON_API_HASH=abc123
Environment=TELETHON_SESSION=1ApWapz...
ExecStart=/opt/telethon/venv/bin/python main.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target# Установка
sudo cp telethon.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable telethon
sudo systemctl start telethon
# Мониторинг
sudo systemctl status telethon
sudo journalctl -u telethon -f[program:telethon]
command=/opt/telethon/venv/bin/python /opt/telethon/main.py
directory=/opt/telethon
user=telethon
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/telethon/supervisor.log
environment=TELETHON_API_ID="123456",TELETHON_API_HASH="abc",TELETHON_SESSION="1Ap..."sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start telethon
sudo supervisorctl tail -f telethonimport logging
import os
os.makedirs('logs', exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
handlers=[
logging.FileHandler('logs/telethon.log'),
logging.StreamHandler() # Также в консоль
]
)
logger = logging.getLogger(__name__)
@client.on(events.NewMessage)
async def logged_handler(event):
logger.info(f'Сообщение из чата {event.chat_id}')
try:
await process(event)
except Exception as e:
logger.error(f'Ошибка: {e}', exc_info=True)from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler(
'logs/telethon.log',
maxBytes=10*1024*1024, # 10 MB
backupCount=5
)import asyncio
from aiohttp import web
async def health_check(request):
if client.is_connected():
return web.Response(text='OK')
else:
return web.Response(text='DISCONNECTED', status=503)
async def start_web_server():
app = web.Application()
app.router.add_get('/health', health_check)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '0.0.0.0', 8080)
await site.start()from prometheus_client import Counter, start_http_server
# Метрики
messages_processed = Counter('messages_processed_total', 'Total messages processed')
errors_total = Counter('errors_total', 'Total errors', ['type'])
flood_wait_total = Counter('flood_wait_seconds_total', 'Total flood wait seconds')
@client.on(events.NewMessage)
async def metrics_handler(event):
messages_processed.inc()
try:
await process(event)
except FloodWaitError as e:
flood_wait_total.inc(e.seconds)
errors_total.labels(type='flood_wait').inc()
except Exception as e:
errors_total.labels(type=type(e).__name__).inc()
raiseimport signal
shutdown_requested = False
async def graceful_shutdown():
global shutdown_requested
shutdown_requested = True
logger.info('Завершение работы...')
await client.disconnect()
@client.on(events.NewMessage)
async def handler(event):
if shutdown_requested:
return # Не обрабатываем новые сообщения
await process(event)#!/bin/bash
# deploy.sh
echo "Stopping service..."
sudo systemctl stop telethon
echo "Pulling latest code..."
git pull origin main
echo "Installing dependencies..."
poetry install --no-dev
echo "Starting service..."
sudo systemctl start telethon
echo "Checking status..."
sleep 5
sudo systemctl status telethon --no-pager# Проверка на уязвимости
pip audit
# Обновление
poetry update# Несколько аккаунтов
clients = []
for session in SESSION_STRINGS:
client = TelegramClient(StringSession(session), api_id, api_hash)
clients.append(client)
# Запуск всех
async def start_all():
for client in clients:
await client.start()
print(f'Клиент {client.session} запущен')
# Обработчики для всех
for client in clients:
@client.on(events.NewMessage)
async def handler(event):
await process(event)┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Telethon │───▶│ Redis/ │───▶│ Worker │
│ Client │ │ Queue │ │ Processor │
└─────────────┘ └──────────────┘ └─────────────┘
# Клиент отправляет задачи в очередь
@client.on(events.NewMessage)
async def enqueue(event):
await redis.lpush('tasks', json.dumps({
'chat_id': event.chat_id,
'text': event.text,
'timestamp': time.time()
}))
# Worker обрабатывает задачи
async def worker():
while True:
_, task_data = await redis.brpop('tasks')
task = json.loads(task_data)
await process_task(task)async def monitor_connection():
while True:
if not client.is_connected():
logger.warning('Клиент отключён. Переподключение...')
try:
await client.connect()
logger.info('Переподключено')
except Exception as e:
logger.error(f'Ошибка переподключения: {e}')
await asyncio.sleep(30)from telethon.errors import UnauthorizedError
try:
await client.get_me()
except UnauthorizedError:
logger.error('Сессия невалидна. Требуется повторная авторизация.')
# Уведомить админа
await notify_admin('Сессия истекла. Требуется авторизация.')Поздравляем! Вы освоили:
Теперь вы готовы создавать production-ready Telethon-приложения!
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.