مهندسی سامانههای یادگیری و مَکنو · فصل ۲ — Discovery، Semantic Diff، Scheduling، Audio، Accessibility و Slides · 302
Background Scheduling برای Updater
قابلیت آموزشی را جداگانه میبیند و learner state، evidence، governance و product architecture را به هم وصل نمیکند. موضوع جاری: «Background Scheduling برای Updater». میتواند «Background Scheduling برای Updater» را در یک سامانهی یادگیری محدود با state/evidence/governance و QA مناسب طراحی کند.
خلاصهٔ درس
قابلیت آموزشی را جداگانه میبیند و learner state، evidence، governance و product architecture را به هم وصل نمیکند. موضوع جاری: «Background Scheduling برای Updater».
میتواند «Background Scheduling برای Updater» را در یک سامانهی یادگیری محدود با state/evidence/governance و QA مناسب طراحی کند.
خروجی این درس
میتواند «Background Scheduling برای Updater» را در یک سامانهی یادگیری محدود با state/evidence/governance و QA مناسب طراحی کند.
وقتی «تایمر اجرا شد» یعنی «Updater دقیقاً یکبار اجرا شد» نیست
سه worker مربوط به updater بعد از شش ساعت قطعی همزمان بالا میآیند. اجرای روزانهی تقویمی عقب افتاده و دو worker همان job را due میبینند؛ در شروع هم وضعیت پایدارِ اجرای قبلی کاملاً روشن نیست. اگر هر دو worker صرفاً از اینکه scheduler trigger داده نتیجه بگیرند که مجاز به اجرا هستند، ممکن است semantic-diff دوبار انجام شود، منبع خارجی بیدلیل تحت فشار قرار گیرد یا تاریخچهی اجرا متناقض شود.
در این درس Updater Scheduling & Lease Contract v1 را میسازیم. trigger فقط یکی از ورودیهاست. برای تصمیم امن، missed_run_policy، jitter محدود، lease با یک مالک معتبر، idempotency key، retry/backoff محدود، شواهد پایدار last/next run، result state و review owner هم لازماند. وقتی این شواهد ناقص یا متناقضاند، پاسخ درست میتواند HOLD باشد، نه «الان اجرا کن».
جایگاه درس و مرز مالکیت
MKN-009 مالک موضوع Background Scheduling برای Updater است. MKN-007 پیشنیاز مفهومی سخت و MKN-008 پیشنیاز نرم است. این درس خروجی «Documentation Monitoring & Semantic Diff» در MKN-008 را دوباره تولید نمیکند و وارد TTS/Word Sync مربوط به MKN-010 هم نمیشود. سؤال محدود ما این است: وقتی updater due شده، چه شواهد پایدارِ schedule، lease، idempotency و retry لازم است تا یک تلاش محدود و قابلممیزی وارد مسیر review شود؟
برای مسیر Foundation نقشهی فیلدها و سناریوی کامل قطعی داریم. در مسیر Repair فقط بعد خرابشده را جدا میکنیم. در مسیر Experienced، learner باید trade-offهای catch-up، jitter، lease TTL و retry را بدون تکیه بر نام یک scheduler توضیح دهد.
مدل ذهنی: trigger → occurrence پایدار → lease → idempotency/history → اجرا → نتیجه → retry یا next run
زنجیرهی تصمیم این است:
trigger due → تشخیص scheduled occurrence → اعمال missed-run policy → گرفتن یک lease → بررسی idempotency/run history → اجرای محدود updater → ثبت نتیجه → retry/backoff یا محاسبه next run → آزاد/منقضیکردن lease
لایهی trigger میگوید چه زمانی کار باید due تلقی شود. لایهی execution تعیین میکند کدام worker برای کدام occurrence حق تلاش دارد. لایهی evidence ثبت میکند واقعاً چه اتفاقی افتاده است. جدا نگهداشتن این سه لایه جلوی این اشتباه را میگیرد که callback scheduler را مدرک exactly-once بدانیم.
قرارداد پایه: هجده بُعد قابل ممیزی
job_id، schedule_type، schedule_expression و timezone هویت schedule را میسازند. last_run_at و next_run_at ترتیب پایدار اجراها را نگه میدارند. missed_run_policy مشخص میکند اجراهای ازدسترفته skip، coalesce یا به یک catch-up محدود تبدیل شوند. jitter_window محدودهی پخش زمان اجرا برای جلوگیری از herd را ثبت میکند.
lease_id، lease_owner و lease_expires_at یک مالک جاری را به occurrence وصل میکنند. idempotency_key کار معنایی را به occurrence متصل میکند تا delivery تکراری و retry قابل تشخیص باشد. attempt، retry_budget و backoff_state بازیابی از خطا را محدود میکنند. run_state و result_ref وضعیت و نتیجه را ثبت میکنند و review_owner مسئولیت انسانی را روشن نگه میدارد.
این فیلدها شواهد هستند؛ scheduler را جادویی exactly-once نمیکنند. ارزششان در آشکارکردن ابهام است.
توضیح عمیق: FACT، INFERENCE و DESIGN را یکی نکن
systemd timer — FACT. timer unitها هم triggerهای monotonic مانند OnBootSec= و OnUnitActiveSec= دارند و هم trigger تقویمی real-time با OnCalendar=. برای calendar timerها، Persistent=true میتواند پس از مدتی inactivity یک اجرای ازدسترفته را هنگام فعالشدن جبران کند. RandomizedDelaySec= نیز میتواند اجراها را در یک بازه پخش کند تا spike همزمان کمتر شود.
تفسیر عملیاتی — INFERENCE. هیچکدام از این قابلیتها اثبات نمیکنند که business work دقیقاً یکبار commit شده است. بعد از restart ممکن است trigger دوباره برسد، چند instance یک occurrence را ببینند، یا side effect خارجی انجام شود ولی ثبت نتیجه محلی شکست بخورد. بنابراین evidence مربوط به last/next run، lease، idempotency، attempt و result باید جدا از schedule expression پایدار باشد.
سیاست MAKNOW — DESIGN. catch-up policy، lease TTL، retry budget، backoff و stateهای review تصمیم محلی پروژهاند. systemd مرجع مکانیزم است، نه مرجع نهایی correctness policy ما.
مثالهای حلشده: بازیابی بعد از قطعی، lease تکراری و انتقال به interval کوتاه
Baseline بعد از قطعی. updater روزانه شش ساعت خاموش بوده است. وضعیت خام ابتدا overdue occurrence و outcome نامعلوم قبلی را نشان میدهد، پس اجرا HOLD میشود. بعد run-history/idempotency بررسی و outcome به NO_COMMITTED_RESULT تبدیل میشود. فقط یک worker lease lease-302-01 میگیرد، missed policy برابر SINGLE_BOUNDED_CATCH_UP است و یک idempotency key پایدار برای همان occurrence داریم. خروجی BOUNDED_CATCH_UP_REVIEW_REQUIRED است؛ نه ادعای «exactly once تضمین شد».
راه میانبُر غلط. دو worker برای یک occurrence، همزمان lease فعال ادعا میکنند. حتی اگر cron expression آنها یکی باشد، قرارداد باید HOLD_CONCURRENT_LEASE_CLAIM بدهد. صحت trigger، ابهام ownership را حل نمیکند.
Transfer. job را از daily calendar به interval پنجدقیقهای در deployment چند-instance تبدیل میکنیم. policy روزانه کپی نمیشود. tickهای قدیمی coalesce میشوند، jitter جدید محاسبه میشود، idempotency key به slot جدید وابسته میشود و lease/retry دوباره بررسی میشوند. فقط بعد از این بازسازی میتوان به INTERVAL_RUN_REVIEW_REQUIRED رسید.
failure modeهایی که باید fail-closed باشند
اگر دو worker lease فعال یکسان را claim کنند، outcome قبلی نامعلوم باشد، lease در حالی منقضی شود که outcome قبلی هنوز نامعلوم است، idempotency key وجود نداشته باشد یا retry budget تمام شده باشد، اجرا باید HOLD شود. next_run_at ناسازگار با last_run_at، jitter خارج از محدوده، backoff نامعلوم برای retry و review owner خالی هم باید مانع تصمیم مثبت شوند.
Restart بعد از missed calendar run نیز بدون missed_run_policy قابل تصمیم نیست. Persistent=true ممکن است در systemd یک activation جبرانی بسازد، اما تعیین نمیکند MAKNOW همه occurrenceهای ازدسترفته را backfill کند، آنها را یکی کند یا مستقیم به اجرای بعدی برود.
گزینهها و trade-offها: calendar، interval، catch-up، jitter و مدت lease
Calendar scheduling برای کاری که معنایش به ساعت/روز تقویمی وابسته است مناسب است، اما timezone، DST و missed run را وارد طراحی میکند. Interval scheduling برای polling منظم مناسبتر است، اما باید روشن باشد interval بعدی نسبت به start، completion یا slot ثابت محاسبه میشود.
Catch-up freshness بعد از downtime را بهتر میکند اما میتواند spike یا کار تکراری بسازد. Skip/coalesce backlog را محدود میکند ولی شاید بعضی مشاهدههای میانی را از دست بدهد. Jitter herd را کاهش میدهد اما jitter زیاد SLA freshness را خراب میکند. Lease طولانی overlap را کم میکند ولی recovery از worker مرده را کند میکند؛ lease کوتاه recovery را سریعتر میکند اما renewal/heartbeat یا idempotency قویتری میخواهد. عدد جهانی و جادویی وجود ندارد؛ قرارداد باید انتخاب و دلیلش را آشکار کند.
پل مسیر Experienced: scheduling را state machine توزیعشده ببین
هر scheduled occurrence باید هویت و state خودش را داشته باشد، نه اینکه فقط callback بینام باشد. طراحی production معمولاً به یک primitive اتمیک برای lease/ownership، شناسهی پایدار occurrence/idempotency و ثبت نتیجهای نیاز دارد که retry را تحمل کند. وعدهی «exactly once» اغلب بیش از حد قوی است؛ طراحی بهتر معمولاً at-least-once delivery همراه با effectهای idempotent/transactionally guarded است، یا HOLD صریح وقتی تکرار effect امن نیست.
Lab عمداً آفلاین و مصنوعی است. ما contract تصمیم را میسنجیم، نه یک database lock یا queue vendor خاص را.
تمرین هدایتشده و مستقل
- baseline قطعی را باز کن و schedule identity، missed-run policy، lease جاری، idempotency key و retry budget را پیدا کن. 2. fixture را طوری تغییر بده که دو worker همان occurrence را acquire کنند و بگو کدام evidence تصمیم را block میکند. 3. بعد از missed calendar run با
missed_run_policy=UNKNOWNrestart کن و catch-up را از خودت نساز. 4. lease را زمانی منقضی کن که outcome قبلی نامعلوم است و توضیح بده چرا تلاش جدید امن نیست. 5. retry budget را تمام کن در حالی که schedule بعدی due میشود؛ due شدن جدید نباید budget تمامشده را دور بزند.
برای تمرین مستقل، expected decision را حذف کن و فقط از evidence قابل مشاهده state را بازسازی کن.
شواهد verification: reviewer باید چه چیزی را بازتولید کند؟
Reviewer باید بتواند بدون reasoning پنهان بازسازی کند: کدام occurrence due است؛ calendar/interval semantics چیست؛ missed occurrence چه میشود؛ jitter داخل bound هست یا نه؛ دقیقاً یک lease owner غیرمنقضی وجود دارد یا نه؛ idempotency key همین کار معنایی را نشان میدهد یا نه؛ outcome قبلی برای retry بهاندازه کافی معلوم است یا نه؛ attempt از retry budget عبور نکرده؛ backoff معتبر است؛ run/result state چه میگوید؛ و review owner چه کسی است.
Lab deterministic رقابت lease، missed policy نامعلوم، outcome نامعلوم، lease expiry، exhausted retry، idempotency گمشده، timeline نامعتبر، jitter خارج از bound، backoff/owner ناقص و reuse ممنوع baseline در transfer را تست میکند.
ارزیابی و Transfer: daily calendar → interval پنجدقیقهای چند-instance
Assessment چهار بخش دارد: اول مرز درس و یک non-goal را توضیح بده؛ دوم baseline Contract را بساز؛ سوم duplicate acquisition دو worker را diagnose کن؛ چهارم schedule را به short interval در deployment چند-instance تبدیل کن.
در transfer باید missed-run behavior، jitter، occurrence identity، lease و retry/backoff از نو محاسبه شوند. کپیکردن SINGLE_BOUNDED_CATCH_UP فقط چون در daily calendar جواب داده، مردود است. نتیجه baseline هیچوقت oracle برای context جدید نیست.
منابع، تازگی و مرز authority
semantics مربوط به systemd timer برای K1/K2 در ۱۳ سپتامبر ۲۰۲۶ دوباره بررسی شد. مستندات جاری همچنان monotonic timer را از OnCalendar جدا میکنند؛ Persistent=true همچنان رفتار catch-up برای calendar timer است و RandomizedDelaySec= همچنان برای پخش بار به کار میرود. این ادعاها تا 2027-01-01 یا زودتر در صورت تغییر مادی semantics دوباره بررسی شوند.
تمام انتخابهای دقیق MAKNOW—نام missed-run policyها، requirementهای lease/idempotency، retry budget، backoff و stateهای bounded decision—DESIGN authority محلی هستند، نه الزام systemd.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
MKN-009-S1 retrieval
MKN-009-S2 application
MKN-009-S3 diagnosis
MKN-009-S4 transfer
ملاکهای ارزیابی (rubric)
A sufficient answer must: (1) keep MKN-009 scope separate from MKN-008/MKN-010; (2) populate all 18 decisive dimensions or mark them explicitly unknown; (3) reject duplicate/expired ownership and unknown prior outcome; (4) never infer exactly-once from scheduler delivery; (5) bound retry/backoff and idempotency evidence; and (6) recompute the interval transfer instead of copying the daily-calendar state. Any missing critical dimension or fabricated success is blocking.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
برای ارزیابی رکورد مصنوعی schedule/lease، python run_checks.py <fixture.json> را اجرا کنید. Lab کاملاً آفلاین است و هیچ timer واقعی، distributed lock، منبع مستندات خارجی یا updater production را تغییر نمیدهد.