הגדרת הפעלה מחדש אוטומטית של בוט מסחר
בוט מסחר פועל 24/7. קריסה עקב שגיאת רשת, OOM, חריגה שלא טופלה או עדכון מערכת — והתהליך מת. ללא הפעלה מחדש אוטומטית, הבוט נשאר מושבת עד שמפעיל מתערב. ככל שההשבתה ארוכה יותר, כך גדלים ההפסדים והסיכון להחמצת אותות מסחר. בסביבת ייצור, אנו משיגים זמינות של 99.9% באמצעות שילוב של systemd, כיבוי מסודר והתראות. נראה כיצד להגדיר זאת באמצעות דוגמה מפרויקט אמיתי: בוט Python עם aiohttp הפועל על Ubuntu 22.04 עם 4 ליבות. אנו משתמשים ב-systemd לניהול, ב-Docker לבידוד וב-Prometheus לניטור.
systemd הוא מנהל השירותים הסטנדרטי בלינוקס. הוא יכול להפעיל מחדש תהליך אוטומטית, להגביל משאבים ולתעד. אך הגדרת Restart=always בלבד אינה מספיקה — יש צורך בהגנה מפני לולאות קריסה. נבחן שלושה מרכיבים מרכזיים: יחידת systemd, כיבוי מסודר בקוד הבוט והתראות על תקלות. עבור בוטים בקונטיינרים, אנו מוסיפים מדיניות הפעלה מחדש של Docker ובדיקות תקינות.
כיצד להגדיר systemd להפעלה מחדש אוטומטית
צור קובץ יחידה ב-/etc/systemd/system/ עם Restart=always ו-RestartSec=10. בנוסף, הגדר StartLimitBurst=5 ו-StartLimitIntervalSec=60 כדי למנוע הפעלות חוזרות אינסופיות על שגיאות קריטיות. הפעל את השירות: systemctl enable trading-bot.
# /etc/systemd/system/trading-bot.service [Unit] Description=Trading Bot After=network-online.target Wants=network-online.target [Service] Type=simple User=botuser WorkingDirectory=/opt/trading-bot ExecStart=/opt/trading-bot/venv/bin/python -u bot.py Restart=always RestartSec=10 StartLimitIntervalSec=60 StartLimitBurst=5 EnvironmentFile=/opt/trading-bot/.env MemoryLimit=2G CPUQuota=80% StandardOutput=journal StandardError=journal SyslogIdentifier=trading-bot [Install] WantedBy=multi-user.target הפעלה:
systemctl daemon-reload systemctl enable trading-bot systemctl start trading-bot journalctl -u trading-bot -f # live логи הפרמטרים # /etc/systemd/system/trading-bot.service [Unit] Description=Trading Bot After=network-online.target Wants=network-online.target [Service] Type=simple User=botuser WorkingDirectory=/opt/trading-bot ExecStart=/opt/trading-bot/venv/bin/python -u bot.py Restart=always RestartSec=10 StartLimitIntervalSec=60 StartLimitBurst=5 EnvironmentFile=/opt/trading-bot/.env MemoryLimit=2G CPUQuota=80% StandardOutput=journal StandardError=journal SyslogIdentifier=trading-bot [Install] WantedBy=multi-user.target + systemctl daemon-reload systemctl enable trading-bot systemctl start trading-bot journalctl -u trading-bot -f # live логи מספקים הגנה מפני לולאות קריסה. בלעדיהם, בוט שממשיך לקרוס יופעל מחדש ללא הגבלה, תוך צבירת שגיאות (פוזיציות פתוחות, הזמנות כפולות). לאחר 5 קריסות מהירות, systemd עוצר את השירות ומפעיל התראה (אם הוגדרה). זה אמין פי 5 ממוניטור cron פשוט.
פרמטרי יחידת systemd: פירוט מפורט
| פרמטר | תיאור | דוגמה |
|---|---|---|
| Restart | מדיניות הפעלה מחדש | always |
| RestartSec | השהיה בין הפעלות מחדש | 10 |
| StartLimitBurst | מגבלת הפעלות מהירות | 5 |
| StartLimitIntervalSec | מרווח זמן למגבלה | 60 |
| MemoryLimit | מגבלת זיכרון | 2G |
| CPUQuota | מכסת מעבד | 80% |
פרמטרים אלה מגבירים את היציבות: הבוט לא קורס מעומסים, ובשגיאות תכופות, systemd חוסם את ההפעלה, ומונע הפסדים עקב הזמנות כפולות.
מהו כיבוי מסודר ולמה הוא נחוץ?
לא ניתן להרוג בוט עם SIGKILL — הוא עלול להשאיר הזמנות פתוחות, פוזיציות שלא נסגרו או התראות שלא נשלחו. טפל ב-SIGTERM:
import signal import asyncio class TradingBot: def __init__(self): self.running = True self.open_orders: list = [] async def shutdown(self): self.running = False for order_id in self.open_orders: try: await self.exchange.cancel_order(order_id) except Exception as e: logger.error(f"Failed to cancel order {order_id}: {e}") logger.info("Graceful shutdown complete") async def run(self): loop = asyncio.get_event_loop() loop.add_signal_handler( signal.SIGTERM, lambda: asyncio.create_task(self.shutdown()) ) while self.running: try: await self.main_loop() except Exception as e: logger.exception(f"Error in main loop: {e}") await asyncio.sleep(5) systemd על StartLimitBurst=5 שולח SIGTERM, ולאחר StartLimitIntervalSec=60 (ברירת מחדל 90 שניות) שולח SIGKILL. עבור בוט עם פוזיציות, 90 שניות בדרך כלל מספיקות.
Docker: חלופה לבוטים בקונטיינרים
אם הבוט פועל ב-Docker, השתמש ב-import signal import asyncio class TradingBot: def __init__(self): self.running = True self.open_orders: list = [] async def shutdown(self): self.running = False for order_id in self.open_orders: try: await self.exchange.cancel_order(order_id) except Exception as e: logger.error(f"Failed to cancel order {order_id}: {e}") logger.info("Graceful shutdown complete") async def run(self): loop = asyncio.get_event_loop() loop.add_signal_handler( signal.SIGTERM, lambda: asyncio.create_task(self.shutdown()) ) while self.running: try: await self.main_loop() except Exception as e: logger.exception(f"Error in main loop: {e}") await asyncio.sleep(5) — הוא מפעיל מחדש על קריסה ואחרי אתחול מארח, אך לא על עצירה ידנית. בדיקת תקינות היא קריטית: Docker מפעיל מחדש קונטיינר רק על קריסה מלאה; תקיעה ללא שגיאה לא תתגלה.
# docker-compose.yml services: trading-bot: image: trading-bot:latest restart: unless-stopped env_file: .env volumes: - ./data:/app/data - ./logs:/app/logs mem_limit: 2g logging: driver: "json-file" options: max-size: "100m" max-file: "5" healthcheck: test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:8080/health', timeout=5)"] interval: 30s timeout: 10s retries: 3 start_period: 60s דוגמה לנקודת תקינות ב-aiohttp:
from aiohttp import web async def health_check(request): last_loop_age = time.time() - bot.last_loop_time if last_loop_age > 300: return web.Response(status=503, text=f"Bot stuck: last loop {last_loop_age:.0f}s ago") if not bot.exchange_connected: return web.Response(status=503, text="Exchange disconnected") return web.Response(status=200, text="OK") app = web.Application() app.router.add_get('/health', health_check) השוואה בין systemd ו-Docker להפעלה מחדש אוטומטית
| פרמטר | systemd | Docker |
|---|---|---|
| מנגנון הפעלה מחדש | יחידת systemd | מדיניות הפעלה מחדש |
| הגנה מפני לולאות קריסה | StartLimitBurst + Interval | אין מובנה (רק תקינות) |
| כיבוי מסודר | SIGTERM + TimeoutStopSec | SIGTERM + stop_grace_period |
| ניטור תקיעות | אין מובנה | בדיקת תקינות |
| המלצה | לשרתי Linux עצמאיים | לתשתית קונטיינרים |
מדוע יש צורך בהתראות על קריסה
עובדת ההפעלה מחדש צריכה ליצור הודעה — גם אם הבוט התאושש אוטומטית. הפתרון המינימלי הוא בוט טלגרם עם שם המארח והשעה. ב-systemd, זה נעשה דרך systemctl stop. עבור Prometheus: כלל TimeoutStopSec. קבל ייעוץ על הגדרת התראות — נמליץ על הפתרון האופטימלי לתשתית שלך.
מה כלול בהגדרת הפעלה מחדש אוטומטית (תוצרים)
- יחידת systemd או תצורת Docker Compose עם הגנה מפני לולאות קריסה
- יישום כיבוי מסודר המטפל בהזמנות פתוחות
- נקודת בדיקת תקינות המאמתת את מצב הבוט והבורסה
- הגדרת התראות (Telegram / Slack) על קריסות והפעלות חוזרות תכופות
- בדיקות בסביבת staging לפני פריסה לייצור
- תיעוד תצורה והוראות לצוות שלך
- 5+ שנות ניסיון בפיתוח בלוקצ'יין — אנו מבטיחים יציבות
דוגמה ללולאת קריסה והשלכותיה
אם הבוט קורס כל 5 שניות עקב שגיאת חיבור לבורסה, ללא StartLimitBurst systemd יפעיל אותו מחדש ללא הגבלה. כל הפעלה עלולה לנסות לבטל הזמנות או ליצור חדשות, מה שמוביל לפוזיציות כפולות. עם StartLimitBurst=5, לאחר הניסיון החמישי, systemd עוצר את השירות ואתה מקבל התראה. זה חוסך ממך הפסדים כספיים.
צור קשר כדי להגדיר את בוט המסחר שלך — אנו מבטיחים פעילות יציבה 24/7. קבל ייעוץ על systemd, Docker והגדרת התראות.







