Add JSON representation of composer.json structure with nodes and edges

This commit is contained in:
hamed
2026-07-08 11:27:54 +03:30
parent 8f4f7fc951
commit 94541ad609
18 changed files with 2157 additions and 688 deletions
@@ -0,0 +1,112 @@
# تشخیص «ری‌استارت» سرور روی 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 یادآوری کن.