ESC را فشار دهید تا بسته شود

رفع خطای start request repeated too quickly در systemd؛ عیب‌یابی سرویس‌هایی که بالا نمی‌آیند

فهرست

خطای start request repeated too quickly یا وضعیت start-limit-hit معمولاً یعنی سرویس چند بار پشت‌سرهم Crash کرده و systemd برای جلوگیری از Crash-loop، شروع دوباره آن را موقتاً محدود کرده است. راه‌حل اصولی این است که اول علت Crash را با systemctl status و journalctl پیدا کنید، بعد سیاست Restart= و RestartSec= و محدودیت‌های StartLimitBurst و StartLimitIntervalSec را بررسی کنید، علت اصلی را رفع کنید و فقط در پایان با systemctl reset-failed شمارنده خطا را پاک و سرویس را دوباره تست کنید.

مرحله ۱: وضعیت سرویس را با systemctl status بررسی کنید

وقتی سرویس بالا نمی‌آید، اولین قدم این است که وضعیت واقعی آن و آخرین خطا را ببینید. به‌جای تکرار مداوم Restart، ابتدا این دستور را اجرا کنید:

sudo systemctl status myapp.service --no-pager -l

در خروجی به بخش‌های Active، Result، کد خروج پردازش و آخرین پیام‌های خطا دقت کنید. اگر عباراتی مثل start request repeated too quickly یا Result: start-limit-hit را می‌بینید، این پیام معمولاً علت اصلی خرابی نیست؛ بلکه نتیجه چند Crash متوالی است.

برای دیدن اطلاعات تکمیلی می‌توانید این دستور را هم اجرا کنید:

sudo systemctl show myapp.service -p Result -p ExecMainStatus -p NRestarts

مرحله ۲: علت Crash را با journalctl پیدا کنید

بعد از مشاهده وضعیت سرویس، لاگ همان Unit را بررسی کنید. مهم‌ترین بخش عیب‌یابی همین مرحله است، چون تا علت Crash مشخص نشود، پاک‌کردن محدودیت systemd فقط مشکل را موقتاً پنهان می‌کند.

sudo journalctl -u myapp.service -b --no-pager -n 100
sudo journalctl -u myapp.service -b -p warning..alert --no-pager

به‌دنبال خطاهایی مثل کانفیگ نامعتبر، Permission denied، پورت اشغال، فایل Environment گم‌شده، مسیر اشتباه در ExecStart، کتابخانه یا Dependency در دسترس‌نبودن و خطای خود اپلیکیشن باشید. اگر سرویس بلافاصله بعد از اجرا Exit می‌کند، معمولاً همین لاگ مشخص می‌کند چرا وارد Crash-loop شده است. برای درک بهتر ساختار لاگ‌ها و نحوه کار journald و journalctl در systemd را هم ببینید.

مرحله ۳: علت واقعی Crash را از Unit و ExecStart مشخص کنید

اگر لاگ نشان می‌دهد مشکل از نحوه اجرای سرویس است، Unit و Overrideهای فعال را ببینید. اگر با ساختار Unitها آشنا نیستید، راهنمای آشنایی با systemd و مدیریت سرویس‌ها مرجع مناسبی است:

sudo systemctl cat myapp.service
sudo systemctl show myapp.service -p FragmentPath -p DropInPaths -p ExecStart

در این مرحله بررسی کنید که مسیر فایل اجرایی، User سرویس، EnvironmentFile، آرگومان‌های اجرای برنامه و Permissionها درست باشند. برای سرویس‌های وب نیز قبل از هر تغییر در StartLimit، کانفیگ خود سرویس را تست کنید:

sudo nginx -t
sudo apachectl configtest
ss -lntp

اگر سرویس اختصاصی دارید، دستور واقعی ExecStart را با همان کاربری که Unit استفاده می‌کند اجرا کنید تا خطای برنامه مستقیم دیده شود.

مرحله ۴: Restart و RestartSec را بررسی کنید

Crash-loop زمانی تشدید می‌شود که سرویس بعد از هر Failure خیلی سریع دوباره اجرا شود. تنظیمات مؤثر Restart را با این دستور ببینید:

systemctl show myapp.service -p Restart -p RestartUSec

اگر Restart=always فعال است، مطمئن شوید واقعاً برای رفتار این سرویس مناسب است. برای بسیاری از Daemonها، Restart=on-failure انتخاب منطقی‌تری است. همچنین RestartSec نباید آن‌قدر کم باشد که سرویس خراب در چند ثانیه چند بار اجرا و دوباره Crash کند.

در صورت نیاز، Override بسازید:

sudo systemctl edit myapp.service
[Service]
Restart=on-failure
RestartSec=5s

هدف از این تغییر، مخفی‌کردن Crash نیست؛ فقط باید بین تلاش‌های بازیابی فاصله منطقی ایجاد شود.

مرحله ۵: StartLimitBurst و StartLimitIntervalSec را بررسی کنید

systemd تعداد Startهای ناموفق را در یک بازه زمانی کنترل می‌کند. برای دیدن مقادیر مؤثر:

systemctl show myapp.service 
  -p StartLimitBurst 
  -p StartLimitIntervalUSec

StartLimitBurst مشخص می‌کند چند تلاش Start در بازه مجاز است و StartLimitIntervalSec بازه زمانی این محاسبه را تعیین می‌کند. اگر سرویس در این بازه بیش از حد Fail شود، systemd آن را با start-limit-hit متوقف می‌کند. اگر اجرای این Unit توسط یک Timer انجام می‌شود، تنظیمات systemd Timer را هم بررسی کنید تا منبع Startهای تکراری اشتباه تشخیص داده نشود.

در صورت نیاز می‌توانید این مقادیر را در Override تنظیم کنید:

sudo systemctl edit myapp.service
[Unit]
StartLimitIntervalSec=60
StartLimitBurst=5

[Service]
Restart=on-failure
RestartSec=5s

نکته مهم: زیادکردن StartLimitBurst یا غیرفعال‌کردن محدودیت، درمان Crash نیست. اگر برنامه در هر Start فوراً خطا می‌دهد، افزایش Limit فقط تعداد Crashها، حجم لاگ و مصرف منابع را بیشتر می‌کند.

مرحله ۶: علت اصلی را قبل از reset-failed اصلاح کنید

حالا خطایی را که در journalctl پیدا کرده‌اید واقعاً رفع کنید؛ مثلاً کانفیگ اشتباه را اصلاح کنید، Permission را درست کنید، پورت متعارض را آزاد کنید، مسیر فایل یا EnvironmentFile را تصحیح کنید یا Dependency موردنیاز برنامه را برگردانید.

اگر Override ساخته‌اید، پس از ذخیره تغییرات این دستور را اجرا کنید:

sudo systemctl daemon-reload

تا زمانی که علت اصلی Crash باقی است، اجرای reset-failed فقط شمارنده را صفر می‌کند و سرویس دوباره خیلی سریع به همان start-limit-hit می‌رسد.

مرحله ۷: systemctl reset-failed را اجرا و سرویس را دوباره تست کنید

بعد از رفع علت Crash، وضعیت Failed و شمارنده Start Limit را پاک کنید:

sudo systemctl reset-failed myapp.service
sudo systemctl start myapp.service
sudo systemctl status myapp.service --no-pager -l

اگر سرویس دوباره بلافاصله Fail شد، Start را پشت‌سرهم تکرار نکنید؛ دوباره به journalctl برگردید و خطای جدید را بررسی کنید.

Verify: مطمئن شوید Crash-loop واقعاً متوقف شده است

فقط Active شدن لحظه‌ای سرویس کافی نیست. چند وضعیت مهم را دوباره بررسی کنید:

systemctl is-active myapp.service
systemctl is-failed myapp.service
systemctl show myapp.service 
  -p Result 
  -p NRestarts 
  -p Restart 
  -p RestartUSec 
  -p StartLimitBurst 
  -p StartLimitIntervalUSec

سرویس باید پایدار بماند، مقدار NRestarts بدون دلیل بالا نرود و در Journal دوباره چرخه سریع Start/Crash دیده نشود. برای چند دقیقه لاگ زنده را هم می‌توانید کنترل کنید:

sudo journalctl -u myapp.service -f

Rollback: اگر Override مشکل‌ساز شد

اگر تغییرات Restart یا StartLimit رفتار نامطلوبی ایجاد کرد، Override را برگردانید:

sudo systemctl revert myapp.service
sudo systemctl daemon-reload
sudo systemctl restart myapp.service

در سرویس‌های Production قبل از تغییر Restart policy یا محدودیت Start، اثر Restart و Downtime را در نظر بگیرید و از تنظیمات فعلی یک نسخه نگه دارید.

اشتباهات رایج هنگام رفع start-limit-hit

فقط reset-failed زدن: اگر علت Crash باقی باشد، سرویس دوباره Fail می‌شود. زیادکردن StartLimitBurst بدون عیب‌یابی: فقط Crash-loop را طولانی‌تر می‌کند. قرار دادن Restart=always برای همه سرویس‌ها: حتی Exit عمدی برنامه می‌تواند Restart ناخواسته ایجاد کند. ویرایش مستقیم فایل Vendor: بهتر است تغییرات محلی با systemctl edit انجام شوند تا آپدیت پکیج آن‌ها را از بین نبرد.

اگر این عیب‌یابی را روی یک سرور مستقل انجام می‌دهید و به منابع اختصاصی برای اجرای پایدار سرویس نیاز دارید، می‌توانید پلن‌های VPS وان‌سرور را بررسی کنید.

5/5 - (1 امتیاز)
اشتراک گذاری نوشته در:

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *