6.9 KiB
Runbook — تشخیص «ریاستارت» سرور: recycle عادی یا خرابی واقعی؟
این سند برای وقتی است که در لاگهای production (Coolify) خطوطی مثل exited: worker-... دیده میشود و بهنظر میرسد «سرور مدام ریاستارت میشود».
خلاصه یکخطی
خروج ساعتیِ workerها با exit status 0; expected طراحیشده و بیضرر است. خرابی واقعی یعنی exit غیرصفر، FATAL، یا قطع شدن پاسخ /health.
۱. چرا workerها هر ساعت restart میشوند؟
هر دو consumer پیام (async و scheduler) با این فلگها اجرا میشوند:
messenger:consume async --time-limit=3600 --memory-limit=128M
messenger:consume scheduler_default --time-limit=3600
--time-limit=3600→ worker بعد از ۱ ساعت خودش با exit code 0 خارج میشود.- supervisord (یا
restart: unless-stoppedدر compose) بلافاصله دوباره آن را بالا میآورد (زیر ۱ ثانیه). - هدف: جلوگیری از نشت حافظه PHP در پروسههای طولانی و تازهکردن اتصالهای کهنه به MariaDB/Redis. الگوی استاندارد و توصیهشده Symfony Messenger است.
به همین دلیل این لاگ عادی است و هیچ اقدامی لازم ندارد:
INFO exited: worker-scheduler (exit status 0; expected)
INFO spawned: 'worker-scheduler' with pid 1464
INFO success: worker-scheduler entered RUNNING state, process has stayed up for > than 1 seconds
کلیدواژه expected یعنی supervisor از قبل میدانست این exit برنامهریزیشده است.
۲. نشانههای خرابی واقعی
اگر هر یک از اینها را دیدید، مشکل واقعی است:
| نشانه در لاگ | معنی |
|---|---|
exited: ... (exit status 1) یا هر عدد غیرصفر |
worker با خطا مرده |
entered FATAL state, too many start retries too quickly |
worker بالا نمیآید (مثلاً DB/Redis در دسترس نیست) |
گپ چند دقیقهای در لاگهای GET /health ... 200 |
وبسرور واقعاً پاسخ نمیداده |
GET /health با status غیر از 200 |
اپ boot نمیشود |
۳. دستورهای تشخیص روی سرور
سؤال اصلی: آیا خود کانتینر ریاستارت شده یا فقط پروسه worker داخل آن recycle شده؟
# وضعیت و uptime کانتینرها — Status باید «Up X hours (healthy)» باشد
docker ps --format 'table {{.Names}}\t{{.Status}}'
# تعداد ریاستارت واقعی و زمان آخرین start کانتینر
docker inspect --format '{{.RestartCount}} {{.State.StartedAt}}' <container-name>
# رویدادهای restart/die در ۲۴ ساعت گذشته
docker events --since 24h --filter event=restart --filter event=die
تفسیر:
RestartCount= 0 وStartedAtقدیمی (مثلاً چند روز پیش) → هیچ ریاستارت واقعیای رخ نداده؛ فقط recycle داخلی worker است.RestartCountبالا یاStartedAtتازه بدون deploy → کانتینر واقعاً crash/restart میشود؛ لاگهای قبل از مرگ را ببینید:docker logs --tail 200 <container>.
۴. اطلاعرسانی خودکار در Coolify
برای اینکه down شدن واقعی بلافاصله خبر داده شود (بهجای پایش دستی لاگ):
- در Coolify → Notifications، یک کانال (Telegram / Email / Discord) فعال کنید.
- رویدادهای «container stopped / unhealthy» و «deployment failed» را روشن کنید.
مستندات:
- https://coolify.io/docs/knowledge-base/notifications
- https://coolify.io/docs/knowledge-base/health-checks
۵. تمدید گواهی TLS (ACME) — مهمترین ریسک down شدن واقعی
علامت مشکل
در access log کانتینر app:
GET /.well-known/acme-challenge/xxxx HTTP/1.1" 404 ... "Let's Encrypt validation server"
چالش HTTP-01 لتسانکریپت باید توسط Traefik (پراکسی Coolify) پاسخ داده شود و اصلاً نباید به کانتینر app برسد. رسیدن آن به app و گرفتن 404 یعنی صدور/تمدید گواهی برای آن دامنه دارد شکست میخورد. اگر رها شود، بعد از انقضای گواهی فعلی، سایت با خطای TLS از دسترس خارج میشود — و این همان «سرور down شد» است.
چکلیست رفع
-
در Coolify → resource اپ → تب Domains: دامنه
clinic-pro.ir(وwww.clinic-pro.irاگر DNS دارد) باید دقیقاً باhttps://روی سرویسappثبت باشد. دامنهای که DNS آن به سرور اشاره میکند ولی در Coolify ثبت نیست، دقیقاً همین الگوی 404 را میسازد. -
تاریخ انقضای گواهی فعلی را چک کنید:
echo | openssl s_client -connect clinic-pro.ir:443 -servername clinic-pro.ir 2>/dev/null \ | openssl x509 -noout -dates -
لاگ پراکسی را برای خطاهای acme ببینید: Coolify → Servers → Proxy → Logs (جستجوی
acme).
مستندات: https://coolify.io/docs/knowledge-base/proxy/traefik/overview
۶. Healthcheckها — رفتار انتظاری
- کانتینر app:
docker/healthcheck.shمسیر واقعی/healthرا از داخل میزند. پارامترها درDockerfileوdocker-compose.ymlیکساناند:interval=15s, timeout=5s, retries=5, start_period=60s. یعنی برای unhealthy شدن باید ۵ بار پیاپی (~۷۵ ثانیه) fail شود. - کانتینرهای worker (حالت compose): healthcheck فقط وجود پروسه
messenger:consumeرا باps | grepچک میکند (interval=30s, retries=3). در لحظه exit ساعتیِ worker ممکن است یک چک fail شود — بیاهمیت است؛ برای unhealthy شدن ۳ شکست پیاپی (~۹۰ ثانیه) لازم است و worker در همان چند ثانیه اول برمیگردد. unhealthy شدن worker فقط وقتی رخ میدهد که consumer واقعاً بالا نیاید (مثلاً Redis در دسترس نباشد).
۷. اعمال تغییرات config
فایلهای docker/supervisord.conf، docker-compose.yml و supervisor.conf باید آینه هم بمانند (workerهای یکسان، فلگهای یکسان). هر تغییری در آنها فقط بعد از Redeploy در Coolify روی سرور اثر میکند.