GitHub Actions و Runnerهای قدیمی؛ چرا Jobها از 31 ژوئیه ممکن است متوقف شوند؟
GitHub از 31 ژوئیه 2026 enforcement نسخه self-hosted runner را برای Enterprise Cloud with Data Residency فعال کرده است. اگر runnerهای سازمانی دارید، این راهنما توضیح می دهد چه نسخه ای برای ثبت لازم است، قانون 30روزه چگونه کار می کند و چطور بدون خواباندن CI یک fleet بزرگ را ارتقا دهید.
چه چیزی در 31 ژوئیه تغییر کرد؟
GitHub از 31 ژوئیه 2026 اجرای حداقل نسخه برای self-hosted runnerها را در GitHub Enterprise Cloud with Data Residency فعال کرده است. این تغییر ناگهانی نیست؛ GitHub از ژوئن جدول brownout و enforcement را منتشر کرده بود تا تیم ها قبل از قطع واقعی jobها runnerهای قدیمی را پیدا کنند. نکته مهم این است که تاریخ 31 ژوئیه برای نسخه Data Residency است و GitHub Enterprise Cloud معمولی طبق جدول رسمی در 25 سپتامبر 2026 وارد full enforcement می شود. بنابراین تیتر «از امروز همه runnerهای قدیمی GitHub از کار افتادند» دقیق نیست.
علت این سخت گیری به معماری تازه زیرساخت Actions برمی گردد. GitHub می گوید backend اجرای job و ارتباط runnerها را بازطراحی کرده و نسخه های قدیمی runner با این بستر جدید قابل پشتیبانی نامحدود نیستند. برای تیم DevOps پیام عملی واضح است: نسخه runner دیگر جزئی از lifecycle زیرساخت است، نه یک باینری که یک بار روی VM نصب شود و سال ها فراموش شود. اگر runner image، autoscaling template یا AMI قدیمی دارید، مسئله فقط ماشین های روشن امروز نیست؛ هر instance جدیدی که از template قدیمی بالا بیاید می تواند دوباره نسخه ناسازگار را وارد fleet کند.
دو قانون جداگانه که معمولاً با هم اشتباه می شوند
| قانون | حداقل/بازه | اگر رعایت نشود |
|---|---|---|
| ثبت یا ثبت مجدد runner | نسخه 2.329.0 یا جدیدتر | runner قدیمی نمی تواند register یا re-register شود. |
| ادامه اجرای job | هر release جدید باید حداکثر ظرف 30 روز اعمال شود | GitHub دیگر job را روی runner عقب افتاده queue نمی کند. |
| به روزرسانی امنیتی بحرانی | بدون مهلت عادی 30 روزه | queue شدن job تا نصب update امنیتی متوقف می شود. |
این تفکیک بسیار مهم است. نسخه 2.329.0 یک «نسخه ثابت برای همیشه» نیست. این عدد حداقل لازم برای registration روی معماری جدید است، اما runnerی که روی همین نسخه pin شود و releaseهای بعدی را نگیرد، پس از عبور از پنجره 30 روزه می تواند job اجرا نکند. در واقع دو محور داریم: compatibility برای وصل شدن به پلتفرم و freshness برای دریافت job. تیمی که فقط اسکریپت bootstrap را از 2.320 به 2.329 تغییر دهد اما سازوکار update نداشته باشد، مشکل را چند هفته عقب انداخته است نه حل.
چه تیم هایی امروز باید فوراً inventory بگیرند؟
بیشترین ریسک برای سازمان هایی است که runner را به صورت long-lived VM یا bare metal نگه می دارند، update خودکار را خاموش کرده اند، یا imageهای immutable را با cadence کند بازسازی می کنند. fleetهای ephemeral هم مصون نیستند؛ اگر Docker image یا VM template آن ها runner قدیمی داشته باشد، هر scale-out نسخه قدیمی را دوباره تولید می کند. در مقابل، runnerهایی که auto-update فعال دارند معمولاً با انتشار نسخه جدید خودشان update می شوند، به شرط آن که به سرویس های لازم شبکه دسترسی داشته باشند و فرایند update در محیط سازمانی مسدود نشده باشد.
تیم هایی که از GitHub Enterprise Cloud with Data Residency استفاده می کنند اکنون باید enforcement را یک وضعیت عملیاتی جاری در نظر بگیرند. تیم های Enterprise Cloud معمولی نیز نباید تا سپتامبر صبر کنند؛ brownoutها از 24 اوت آغاز می شوند و مرحله به مرحله ثبت و اجرای runnerهای عقب افتاده را مختل می کنند. GitHub Enterprise Server در اعلامیه فعلی مشمول این migration نیست، پس اگر محیط شما GHES است لازم است برنامه پشتیبانی همان نسخه سرور را جدا بررسی کنید و این timeline را کورکورانه روی آن اعمال نکنید.
چطور نسخه runnerهای سازمان را پیدا کنیم؟
برای fleet کوچک می توانید از تنظیمات repository یا organization شروع کنید، اما در مقیاس سازمانی نگاه کردن دستی به چند ده صفحه قابل اتکا نیست. GitHub نسخه runner را در REST API self-hosted runners برمی گرداند. این یعنی می توانید inventory را به یک job دوره ای تبدیل کنید، نسخه ها را با policy داخلی مقایسه کنید و runnerهای offline یا عقب افتاده را جدا کنید. مزیت API نسبت به audit log این است که inventory فعلی runnerهای ثبت شده را می بینید؛ audit log بیشتر برای رویدادهای registration مناسب است و لزوماً تصویر کامل تمام runnerهای متصل را نمی دهد.
curl -L \
-H 'Accept: application/vnd.github+json' \
-H 'Authorization: Bearer <TOKEN>' \
-H 'X-GitHub-Api-Version: 2026-03-10' \
https://api.github.com/orgs/ORG/actions/runnersدر پاسخ API فیلد version کنار name، os، status، busy و ephemeral قرار می گیرد. به جای hard-code کردن یک شماره «مجاز»، بهتر است policy را بر اساس release age تعریف کنید: آیا این نسخه بیش از 30 روز از releaseهای جدید عقب است؟ آیا update بحرانی منتشر شده؟ آیا runner از imageای ساخته شده که هنوز rebuild نشده است؟ این مدل از rule ثابت پایدارتر است، چون حداقل واقعی اجرای job با انتشار releaseهای جدید جلو می رود.
اگر runnerها immutable یا containerized هستند چه کنیم؟
در fleetهای ephemeral معمولاً update داخل runner غیرفعال می شود تا image در زمان اجرا تغییر نکند. این الگو همچنان معتبر است، اما مسئولیت update از خود runner به pipeline ساخت image منتقل می شود. در چنین معماری ای باید release جدید actions/runner یک signal برای rebuild image باشد. image جدید را در یک canary pool بالا بیاورید، چند workflow نماینده را اجرا کنید، سپس poolهای قدیمی را drain و حذف کنید. اگر فقط image tag را latest گذاشته اید اما layer cache یا AMI parent قدیمی است، verify کنید باینری runner واقعاً تغییر کرده باشد.
در Kubernetes و autoscalerهای سفارشی، مشکل رایج دیگری وجود دارد: controller ممکن است pod یا VM جدید را از template قدیمی بسازد و fleet ظاهراً بعد از patch دوباره regress کند. برای جلوگیری از این وضعیت، نسخه runner باید بخشی از desired state باشد؛ مثلاً image digest یا version label را در GitOps repository نگه دارید و روی آن alert بسازید. هدف این است که «نسخه runner» مثل نسخه base image یا runtime قابل مشاهده و review باشد، نه جزئی مخفی در startup script.
Auto-update خوب است یا --disableupdate؟
GitHub به صورت پیش فرض runner را خودکار update می کند. این گزینه برای سرورهای long-lived ساده ترین راه رعایت window است، اما در محیط های سخت گیر ممکن است تغییر باینری بدون فرایند release داخلی قابل قبول نباشد. در آن شرایط flag مربوط به غیرفعال کردن update می تواند منطقی باشد، به شرط آن که تیم یک pipeline جایگزین واقعی داشته باشد. خاموش کردن auto-update بدون owner، SLA و alert صرفاً انتقال مسئولیت به جایی نامعلوم است.
اگر update دستی دارید، release cadence را به change management وصل کنید. مثلاً هر release جدید runner یک ticket خودکار ایجاد کند، image build شود، smoke test اجرا شود و حداکثر در چند روز rollout کامل شود. پنجره 30 روز را به عنوان deadline نهایی ببینید، نه هدف rollout. چون GitHub می تواند برای critical security update queue را زودتر متوقف کند، تیمی که همیشه روز 29 update می کند عملاً margin امنیتی ندارد.
نشانه های شکست بعد از enforcement چیست؟
علامت مشکل همیشه یک error روشن با متن «runner شما قدیمی است» نیست. ممکن است workflow مدت زیادی queued بماند، runner جدید register نشود، یا pool autoscaled ظرفیت داشته باشد ولی job به آن assign نشود. قبل از بررسی YAML workflow، version و سلامت runner را در triage اولیه قرار دهید. اگر فقط یک گروه runner مشکل دارد، تفاوت image و version آن گروه را با pool سالم مقایسه کنید. همچنین annotationهایی که GitHub پیش از enforcement روی runtime نشان می دهد باید وارد alerting یا حداقل runbook تیم شوند.
تفکیک config failure از runtime failure نیز مهم است. یک runner خیلی قدیمی ممکن است اصلاً registration را انجام ندهد؛ runner دیگری ممکن است register شده باشد اما به دلیل عقب افتادگی از releaseهای جدید دیگر job نگیرد. این دو سناریو remediation متفاوتی دارند. در اولی bootstrap image و registration script را اصلاح می کنید؛ در دومی update cadence و fleet replacement را. اگر هر دو را با reinstall دستی روی یک ماشین درمان کنید، احتمال بازگشت خطا زیاد است.
برنامه مهاجرت کم ریسک برای fleet بزرگ
- از REST API inventory کامل runnerها را بگیرید و version، status، scope و pool را ثبت کنید.
- منبع ساخت هر runner را پیدا کنید: VM ثابت، AMI، container image، Kubernetes pod یا autoscaler اختصاصی.
- runnerهای زیر 2.329.0 را برای registration فوری در اولویت قرار دهید و runnerهای خارج از پنجره release را جدا کنید.
- image یا installation source را به نسخه جدید ارتقا دهید؛ patch دستی ماشین تنها راه حل پایدار نیست.
- یک canary pool بسازید و workflowهای شامل cache، artifact، container، OIDC و service container را روی آن تست کنید.
- پس از موفقیت، poolهای قدیمی را drain کنید و از حذف کامل template قدیمی مطمئن شوید.
- alert بر اساس version age و انتشار release جدید بسازید و owner مشخص برای patching تعیین کنید.
- برای critical security release یک مسیر emergency rollout کوتاه تر از فرایند عادی داشته باشید.
Timeline را درست بخوانید
| محیط | شروع brownout / enforcement | وضعیت |
|---|---|---|
| GitHub Enterprise Cloud with Data Residency | Full enforcement از 31 ژوئیه 2026 | اکنون فعال |
| GitHub Enterprise Cloud | Brownout از 24 اوت؛ Full enforcement از 25 سپتامبر 2026 | زمان آماده سازی باقی است |
| GitHub Enterprise Server | در این اعلامیه مشمول نیست | برنامه نسخه GHES جدا بررسی شود |
این timeline فرصت خوبی برای استانداردکردن fleet قبل از رسیدن deadline دوم است. اگر سازمان شما Data Residency ندارد، نتیجه نباید «پس فعلاً کاری نکنیم» باشد. برعکس، می توانید از تجربه تیم های موج اول استفاده کنید و قبل از brownoutهای اوت، inventory، image pipeline و alertها را کامل کنید. مهاجرت وقتی کم ریسک است که در روز عادی انجام شود، نه زمانی که queue تولید متوقف شده و همه دنبال نسخه runner می گردند.
پرسش های متداول
حداقل نسخه برای ثبت self-hosted runner در معماری جدید چیست؟
GitHub نسخه 2.329.0 یا جدیدتر را برای registration یا re-registration لازم می داند.
آیا ماندن روی 2.329.0 کافی است؟
خیر. برای اجرای job باید releaseهای جدید runner را حداکثر در پنجره 30 روزه اعمال کنید.
اگر auto-update را خاموش کنیم چه می شود؟
مجاز است، اما باید runner را با فرایند خودتان منظم update کنید؛ در غیر این صورت jobها دیگر queue نمی شوند.
آیا critical security update هم 30 روز فرصت دارد؟
GitHub می گوید در صورت update امنیتی بحرانی، queue شدن job تا نصب update متوقف می شود.
آیا 31 ژوئیه همه GitHub Enterprise Cloudها را شامل می شود؟
خیر. 31 ژوئیه full enforcement برای Enterprise Cloud with Data Residency است؛ Enterprise Cloud معمولی 25 سپتامبر 2026 full enforcement دارد.
GitHub Enterprise Server هم مشمول است؟
طبق اعلامیه این تغییر در حال حاضر GHES را تحت تأثیر قرار نمی دهد.
منابع رسمی و جمع بندی
جزئیات deadline و brownout در اعلامیه رسمی GitHub درباره حداقل نسخه self-hosted runner آمده است. رفتار update و پنجره 30 روزه در مرجع رسمی self-hosted runners توضیح داده شده و برای inventory نسخه ها می توانید از REST API رسمی self-hosted runners استفاده کنید.
جمع بندی: این تغییر یک «شماره نسخه جدید» نیست؛ GitHub عملاً runner freshness را به بخشی از قرارداد سرویس تبدیل کرده است. راه حل پایدار این است که version inventory، image build، canary rollout و alert را اتومات کنید. اگر runner را مثل یک dependency زیرساخت مدیریت کنید، enforcement بعدی یک maintenance معمولی خواهد بود. اگر آن را باینری فراموش شده روی چند VM بدانید، اولین نشانه مشکل احتمالاً queue متوقف شده CI خواهد بود.