113 lines
8.6 KiB
Markdown
113 lines
8.6 KiB
Markdown
# تشخیص «ریاستارت» سرور روی Coolify + رفع نویز لاگ + بررسی خطای ACME
|
|
|
|
## پروژه
|
|
|
|
`clinicpro` (فقط فایلهای deploy — بدون تغییر در کد PHP/React)
|
|
|
|
## زمینه
|
|
|
|
کاربر در لاگهای production (Coolify روی Ubuntu) میبیند که workerها مدام exit/spawn میشوند و نگران است سرور down میشود. تحلیل لاگ ارائهشده:
|
|
|
|
```
|
|
2026-07-08 07:40:54,435 INFO exited: worker-scheduler (exit status 0; expected)
|
|
2026-07-08 07:40:54,457 INFO spawned: 'worker-scheduler' with pid 1464
|
|
2026-07-08 07:40:54,460 INFO exited: worker-async (exit status 0; expected)
|
|
2026-07-08 07:40:54,468 INFO spawned: 'worker-async' with pid 1465
|
|
2026-07-08 07:40:55,674 INFO success: worker-async entered RUNNING state ...
|
|
```
|
|
|
|
**این crash نیست.** این رفتار طراحیشده است:
|
|
|
|
- `docker/supervisord.conf` هر دو worker را با `--time-limit=3600` اجرا میکند → هر worker دقیقاً هر ۱ ساعت با exit code 0 خارج میشود (به همین دلیل supervisor مینویسد `expected`).
|
|
- supervisord با `autorestart=true` در کمتر از ۱ ثانیه دوباره spawn میکند.
|
|
- در تمام مدت لاگ، `GET /health` هر ۱۵ ثانیه `200` برگردانده — یعنی nginx + php-fpm (وبسرور اصلی) هرگز down نبوده.
|
|
- recycle ساعتیِ consumer الگوی استاندارد Symfony Messenger است (جلوگیری از نشت حافظه و connection کهنه به DB/Redis). مستندات Coolify هم healthcheck/restart policy را همینطور توصیه میکند.
|
|
|
|
**اما یک مشکل واقعی در لاگ هست** که میتواند در آینده باعث «down شدن» واقعی (خطای TLS) شود:
|
|
|
|
```
|
|
GET /.well-known/acme-challenge/hb1abFQX9d-... HTTP/1.1" 404
|
|
"Mozilla/5.0 (compatible; Let's Encrypt validation server; ...)"
|
|
```
|
|
|
|
سرور validation لتسانکریپت برای دامنه `clinic-pro.ir` چالش HTTP-01 فرستاده و به جای اینکه Traefik (پراکسی Coolify) خودش جواب بدهد، درخواست به کانتینر app رسیده و 404 گرفته. اگر این وضع ادامه پیدا کند تمدید گواهی شکست میخورد و بعد از انقضای cert فعلی، سایت با خطای TLS از دسترس خارج میشود — کاربر آن را «سرور down شد» میبیند.
|
|
|
|
## فایلهای مرتبط
|
|
|
|
| فایل | نقش |
|
|
|------|-----|
|
|
| `docker/supervisord.conf` | supervisor داخل کانتینر: nginx + php-fpm + دو worker با `--time-limit=3600 -v` |
|
|
| `docker-compose.yml` | حالت Compose در Coolify: app + دو worker بهصورت سرویس جدا، همان `--time-limit=3600 -v` |
|
|
| `supervisor.conf` | نسخه Liara — همان الگو |
|
|
| `docker/healthcheck.sh` | healthcheck کانتینر: `GET /health` → exit 0/1 |
|
|
| `Dockerfile` | `HEALTHCHECK --interval=15s --retries=5 --start-period=60s` |
|
|
| `docs/` | مقصد runbook جدید |
|
|
|
|
## وضعیت فعلی
|
|
|
|
`docker/supervisord.conf`:
|
|
|
|
```ini
|
|
[program:worker-async]
|
|
command=php bin/console messenger:consume async --time-limit=3600 --memory-limit=128M -v
|
|
autorestart=true
|
|
|
|
[program:worker-scheduler]
|
|
command=php bin/console messenger:consume scheduler_default --time-limit=3600 -v
|
|
autorestart=true
|
|
```
|
|
|
|
فلگ `-v` باعث میشود هر بار restart شدن worker، بنر چندخطی «[OK] Consuming messages…» و «The worker will automatically exit…» در stdout چاپ شود — همین بنرها لاگ را شلوغ و «ریاستارت» را ترسناکتر از واقعیت نشان میدهند.
|
|
|
|
## وظایف
|
|
|
|
### ۱. کاهش نویز لاگ workerها (بدون تغییر رفتار)
|
|
|
|
فلگ `-v` را از هر چهار محل حذف کن (دو program در `docker/supervisord.conf`، دو service در `docker-compose.yml`، دو program در `supervisor.conf`). `--time-limit=3600` و `--memory-limit=128M` را **دست نزن** — recycle ساعتی عمداً وجود دارد و باید بماند.
|
|
|
|
```ini
|
|
command=php bin/console messenger:consume async --time-limit=3600 --memory-limit=128M
|
|
```
|
|
|
|
خطاهای واقعی worker همچنان از طریق monolog (stderr) دیده میشوند؛ `-v` فقط verbosity کنسول بود.
|
|
|
|
### ۲. Runbook تشخیص «restart واقعی» از «recycle عادی»
|
|
|
|
فایل `docs/ops-restarts.md` بساز (فارسی) با این محتوا:
|
|
|
|
- توضیح اینکه `exited (exit status 0; expected)` + spawn فوری = recycle عادی و بیضرر است؛ نشانههای مشکل واقعی: `exit status` غیرصفر، `entered FATAL state`، `too many start retries`، یا گپ در لاگهای `/health`.
|
|
- دستورهای تشخیص روی سرور:
|
|
|
|
```bash
|
|
# آیا خودِ کانتینر ریاستارت شده؟ (uptime کانتینر vs uptime پروسه)
|
|
docker ps --format 'table {{.Names}}\t{{.Status}}' # Status باید Up X hours (healthy) باشد
|
|
docker inspect --format '{{.RestartCount}} {{.State.StartedAt}}' <container>
|
|
docker events --since 24h --filter event=restart --filter event=die
|
|
```
|
|
|
|
- اگر `RestartCount` صفر است و `StartedAt` قدیمی → هیچ ریاستارت واقعیای در کار نیست؛ فقط recycle داخلی worker است.
|
|
- بخش Coolify: فعالکردن Notifications (Telegram/Email) در Coolify برای event های container stop/unhealthy، تا down شدن واقعی بلافاصله اطلاع داده شود. ارجاع به مستندات: `https://coolify.io/docs/knowledge-base/notifications` و `https://coolify.io/docs/knowledge-base/health-checks`.
|
|
|
|
### ۳. بررسی و مستندسازی خطای ACME (مهمترین ریسک down شدن واقعی)
|
|
|
|
در همان `docs/ops-restarts.md` بخش «تمدید گواهی TLS» اضافه کن:
|
|
|
|
- علامت مشکل: `GET /.well-known/acme-challenge/... → 404` در access log کانتینر app. چالش HTTP-01 باید توسط Traefik خود Coolify جواب داده شود و اصلاً نباید به app برسد؛ رسیدنش یعنی صدور/تمدید cert برای آن دامنه دارد شکست میخورد.
|
|
- چکلیست رفع روی سرور Coolify:
|
|
1. در Coolify → resource مربوط به app → تب Domains: مطمئن شو دامنه `clinic-pro.ir` (و `www` اگر لازم است) دقیقاً با schema `https://` روی سرویس `app` ثبت شده باشد. دامنهای که در Coolify ثبت نشده ولی DNS آن به سرور اشاره میکند، همین الگوی 404 را میسازد.
|
|
2. وضعیت فعلی cert را چک کن: `echo | openssl s_client -connect clinic-pro.ir:443 -servername clinic-pro.ir 2>/dev/null | openssl x509 -noout -dates`
|
|
3. لاگ Traefik/proxy در Coolify (Servers → Proxy → Logs) را برای خطای acme بررسی کن.
|
|
- ارجاع: `https://coolify.io/docs/knowledge-base/proxy/traefik/overview` و بخش Domains در مستندات Coolify.
|
|
|
|
### ۴. سازگاری healthcheck
|
|
|
|
فقط بررسی (بدون تغییر مگر مغایرت پیدا شد): `Dockerfile` مقادیر `interval=15s, retries=5, start-period=60s` دارد و `docker-compose.yml` سرویس app همان مقادیر را — مطمئن شو یکسان بمانند. healthcheck های worker در compose (`ps | grep messenger:consume`) در لحظه exit ساعتیِ worker ممکن است یک بار fail شوند؛ چون `retries: 3` و `interval: 30s` است، سه شکست پیاپی لازم است و restart کانتینر (که Coolify آن را event میکند) رخ نمیدهد مگر worker واقعاً بالا نیاید — این را در runbook هم ذکر کن.
|
|
|
|
## نکات مهم
|
|
|
|
- **هیچ تغییری در رفتار runtime نده** جز حذف `-v`. `--time-limit` و `autorestart` عمدی و صحیحاند.
|
|
- این پرامپت فایل PHP/React را لمس نمیکند → migration و بهروزرسانی `docs/api/` لازم ندارد.
|
|
- `docs/ops-restarts.md` فارسی نوشته شود (زبان محصول)، ولی دستورها و خروجیهای shell انگلیسی بمانند.
|
|
- سه فایل config (`docker/supervisord.conf`، `docker-compose.yml`، `supervisor.conf`) باید بعد از تغییر همچنان آینه هم بمانند — کامنتهای بالای هر فایل همین را میگویند.
|
|
- بعد از merge، اعمال روی سرور نیاز به redeploy در Coolify دارد؛ در runbook یادآوری کن.
|