كيفيّة إنشاء خدمات Windows وتشغيلها ── من التمييز عن جدولة المهام إلى تحويل BackgroundService إلى خدمة
· آخر تحديث: · غو كومورا · خدمة Windows, Windows, .NET, C#, BackgroundService, Generic Host, المعالجة المقيمة, التشغيل, جدول القرار, الاستشارات التقنية
سجل التعديلات (2 تحديثات، آخر تحديث 2 Sep، 2026)
سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.
- أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
- أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
- النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621599)
هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.
غو كومورا (2026). كيفيّة إنشاء خدمات Windows وتشغيلها ── من التمييز عن جدولة المهام إلى تحويل BackgroundService إلى خدمة. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621599 https://comcomponent.com/ar/blog/windows-service-worker-service-guide/
- DOI (أحدث نسخة)
- 10.5281/zenodo.21621599
- DOI (هذه النسخة)
- 10.5281/zenodo.22240986
«لم تعد جدولة المهام كلّ 5 دقائق كافية» أو «نريد تشغيل خادوم مراقبة مقيم ينتظر باستمرار بيانات قادمة من الجهاز» أو «نريد معالجة الملفّ خلال ثوانٍ قليلة من وضعه في المجلّد». عند متابعة استشارات التنفيذ الدوريّ، يصل الأمر دائماً إلى هذا الموضوع بعد أن تنمو المتطلّبات.
كتبنا في هذه المدوّنة تباعاً عن الأتمتة: أتمتة الأعمال عبر Power Automate، وتصميم تشغيل آمن لـ Task Scheduler. وفي الفصل 8 من مقال Task Scheduler ذكرنا الخطّ: «إذا لزم الاستقصاء بالدقيقة أو المراقبة الدائمة فذلك مجال العمليّة المقيمة». فكيف تُنشأ خدمة Windows فعلاً وكيف تُحمَل على التشغيل؟ إن بقي الأمر غامضاً و«حُوِّلت إلى خدمة على أيّ حال» وُلدت «خدمة لا يمكن إيقافها» و«خدمة سقطت دون أن يلاحظ أحد» و«خدمة تعمل بكلّ شيء تحت LocalSystem».
يرتب هذا المقال، بالترتيب الذي يُحسَم به في العمل، جدول قرار ما إذا كانت المعالجة المقيمة ينبغي أن تكون خدمة Windows، والحدّ الأدنى من معرفة آليّة الخدمة (SCM = مدير التحكّم بالخدمات، وأنواع البدء، وSession 0)، والتنفيذ عبر Worker Service في .NET 8، والتسجيل وخيار الاسترداد عبر sc.exe، واختيار حساب التنفيذ، ثمّ معالجة الإيقاف الآمن.
1. الخلاصة أوّلاً
- محور التمييز ── المعالجة الدوريّة بفاصل لا يقلّ عن بضع دقائق تكفي لها جدولة المهام. إذا دخل ضمن المتطلّبات الانتظار الدائم (مقبس، أنبوب مسمّى، FileSystemWatcher) أو الاستجابة بالثانية أو الاسترداد التلقائيّ عند السقوط، فالخيار خدمة Windows.
- لا يمكن عرض واجهة ── ابتداءً من Windows Vista تعمل الخدمات في Session 0، ولا يمكنها التفاعل مباشرة مع المستخدم (لا تعرض واجهة). إن لزمت الواجهة فافصل الخدمة عن تطبيق الواجهة وتخاطبا عبر الاتّصال بين العمليّات (IPC).1
- مسار التنفيذ ── طريقة الإنشاء في .NET هي قالب Worker Service مع
AddWindowsServiceمنMicrosoft.Extensions.Hosting.WindowsServices(UseWindowsServiceفي سلسلةIHostBuilder). يمكن تشغيله كما هو كتطبيق سطر أوامر، فيصير التطوير والتصحيح أسهل بكثير من تطوير الخدمات التقليديّ.2 - الاستثناءات وإعادة التشغيل ── ابتداءً من .NET 6، الاستثناء غير المعالَج داخل
BackgroundServiceيوقف المضيف افتراضيّاً (BackgroundServiceExceptionBehavior.StopHost). غير أنّ هذا «إيقاف طبيعيّ»، لذا لا يعمل إعادة التشغيل عبر خيار استرداد SCM (مدير التحكّم بالخدمات). الفشل الذي تريد إعادة تشغيله تُسقِط فيه العمليّة برمز خروج غير صفريّ.32 - حساب التنفيذ ── لا تختر LocalSystem بدافع الكسل. افتراضيّ
sc.exe createهو LocalSystem، فإن لم تنتبه بدأت بأقوى صلاحيّة.4 إن اكتمل الأمر محلّيّاً فـ LocalService أو حساب افتراضيّ، وإن لمست مشاركة أو قاعدة بيانات في النطاق فالخيار الجادّ gMSA (Group Managed Service Account، حساب خدمة مُدار جماعيّاً؛ حساب مخصّص يدير النطاق كلمة مروره تلقائيّاً).5 - الاسترداد والإيقاف ── خيار الاسترداد (
sc.exe failure) ومعالجة الإيقاف (HostOptions.ShutdownTimeout، الافتراضيّ 30 ثانية6) يُصمَّمان عند التسجيل. «الخدمة التي لا تستجيب للإيقاف» أكثر ما يكرهه التشغيل.
في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 19، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle
2. متى ينبغي تحويلها إلى خدمة ── جدول قرار بين جدولة المهام والخدمة والتطبيق المقيم
عندما يظهر متطلّب شبيه بالإقامة، الخيارات ثلاثة: جدولة المهام، وخدمة Windows، و«تطبيق مقيم مسجَّل في بدء التشغيل» (النوع الذي يقيم في منطقة الإشعارات). نرتّب الطبيعة.
| الجانب | جدولة المهام | خدمة Windows | تطبيق مقيم (تسجيل بدء التشغيل) |
|---|---|---|---|
| توقيت البدء | يبدأ كلّ مرّة بوقت أو حدث | مقيم من إقلاع نظام التشغيل (قبل تسجيل الدخول) | من تسجيل دخول المستخدم |
| هل يغني عن تسجيل الدخول | يمكن جعله غير لازم (تنفيذ غير تفاعليّ) | غير لازم | لازم (يختفي عند تسجيل الخروج) |
| الواجهة | لا تُعرض (في التكوين غير التفاعليّ) | لا تُعرض (Session 0) | تُعرض (منطقة إشعارات وحوارات) |
| دائم أم دوريّ | دوريّ (مناسبه من الساعة إلى اليوم) | دائم | دائم (لكن داخل جلسة المستخدم) |
| الصلاحيّات | حساب تنفيذ لكلّ مهمّة | حساب خدمة (الفصل 6) | صلاحيّات مستخدم تسجيل الدخول |
| المراقبة والاسترداد | السجلّ + إشعار ذاتيّ | خيار استرداد SCM (إعادة تشغيل تلقائيّة) | لا شيء (تُبنى ذاتيّاً) |
| عبء التوزيع | تسجيل بـ XML / PowerShell | sc.exe / مثبِّت | تسجيل في مفتاح Run وغيره |
محور الحكم كالتالي.
- معالجة دوريّة عدّة مرّات في اليوم إلى مرّة في الساعة، بلا حالة بين المرّات فجدولة المهام. تحويل هذا إلى خدمة تدير المؤقّت بنفسك إفراط، وتصميم التشغيل في مقال Task Scheduler أرخص بكثير.
- إن كان الانتظار الدائم هو الجوهر ── انتظار طلب عبر TCP أو أنبوب، ومراقبة مجلّد عبر FileSystemWatcher، ومعالجة طابور بالتتابع، واستجابة بالثانية ── فخدمة Windows. وإذا بدأتَ تقطيع الاستقصاء بـ«مهمّة كلّ 5 دقائق»، فتلك إشارة إلى أنّك تعيد تنفيذ عمليّة مقيمة بشكل متدهور.
- إن كانت الواجهة هي الجوهر (تشغيل من منطقة الإشعارات، نوافذ منبثقة للمستخدم) فتطبيق مقيم. غير أنّه لا يعمل بلا تسجيل دخول، فلا يصلح لاستعمال شبيه بالخادم. إن لزم «معالجة خلفيّة دائمة وواجهة أيضاً» فافصل كما في الفصل التالي إلى عمليّتين: خدمة وتطبيق واجهة.
ومادّة حكم كثيراً ما تُغفل: الاسترداد. مهمّة جدولة المهام إن فشلت تُترَك إلى الجدول التالي، أمّا الخدمة فيتولّى SCM إعادة التشغيل التلقائيّة (الفصل 5). متطلّب «إن سقطت ليلاً نريدها قد عادت وحدها قبل الصباح» سبب بذاته للتحويل إلى خدمة.
3. الحدّ الأدنى من المعرفة بآليّة عمل الخدمات ── SCM وأنواع بدء التشغيل وSession 0
3.1 SCM وأنواع بدء التشغيل
صاحب خدمات Windows هو مدير التحكّم بالخدمات (SCM). يدير سجلّ الخدمات، ويتوسّط طلبات البدء والإيقاف، وينفّذ سلوك الاسترداد عند الفشل. يجب أن تكون عمليّة الخدمة قادرة على محادثة SCM وفق الاتفاق، غير أنّ مكتبة .NET تتولّى هذا الجزء نيابة عنّا (الفصل 4)، وما نقرّره كتصميم هو أربع نقاط: «نوع البدء» و«حساب التنفيذ» و«الاسترداد» و«الإيقاف».
أنواع البدء (نوع بدء التشغيل) أربعة خيارات.4
| نوع البدء | السلوك | موضع الاستخدام |
|---|---|---|
| تلقائيّ (auto) | يبدأ عند إقلاع نظام التشغيل | الأساس للخدمة الدائمة |
| تلقائيّ متأخّر (delayed-auto) | يبدأ بعد الخدمات التلقائيّة بقليل | ابدأ خدمات الأعمال بهذا. يتجنّب ازدحام ما بعد الإقلاع وعدم جاهزيّة التبعيّات |
| يدويّ (demand) | يبدأ عند الطلب فقط | خدمة مساعدة يشغّلها تطبيق آخر |
| معطَّل (disabled) | لا يمكن البدء | إجراء إيقاف أو ختم |
اجعل لخدمات الأعمال البدء المتأخّر افتراضيّاً. فور إقلاع نظام التشغيل لا تكون الشبكة ولا قاعدة البيانات ولا الخدمات الأخرى مكتملة، فالبدء «تلقائيّاً» بأقصى سرعة كثيراً ما يفشل الاتّصال الأوّل. التركيب الثابت: فارق زمنيّ بالبدء المتأخّر، وامتصاص فشل الاتّصال بإعادة المحاولة داخل ExecuteAsync كما سيأتي.
وأعرف أيضاً مهلة البدء. لا ينتظر SCM بلا نهاية تقرير اكتمال بدء الخدمة. إن تجاوزت المهلة الافتراضيّة (ServicesPipeTimeout، 30 ثانية) سُجِّل الحدث 7000 / 7011 وعُدّ البدء فاشلاً.7 أي لا تضع تهيئة ثقيلة مثل إعادة محاولة الاتّصال بقاعدة البيانات أو بناء تخزين مؤقّت كبير «داخل معالجة البدء». القاعدة الحديديّة: أكمل البدء سريعاً، واترك المعالجة الثقيلة لحلقة الجسم (ExecuteAsync).
إن جُمعت محادثة SCM وعمليّة الخدمة في صورة واحدة، فالمسار التالي. البدء والإيقاف كلاهما ذهاب وإياب بين «طلب» و«تقرير اكتمال»، ووجود حدّ زمنيّ لهذا الذهاب والإياب سمة الخدمة.
sequenceDiagram
participant Adm as المدير / إقلاع نظام التشغيل
participant SCM as SCM
participant Svc as عمليّة الخدمة
participant BG as BackgroundService
Adm->>SCM: طلب بدء sc.exe start أو بدء تلقائيّ
SCM->>Svc: تشغيل العمليّة
Svc-->>SCM: تقرير أنّ البدء جارٍ START_PENDING
Note over SCM,Svc: إن تعذّر تقرير التشغيل خلال ServicesPipeTimeout الافتراضيّ 30 ثانية يُسجَّل الحدث 7000 / 7011
Svc-->>SCM: تقرير التشغيل SERVICE_RUNNING
Svc->>BG: بدء ExecuteAsync
BG-->>BG: حلقة انتظار ومعالجة
Adm->>SCM: طلب إيقاف sc.exe stop أو إيقاف التشغيل
SCM->>Svc: إشعار بطلب الإيقاف
Svc->>BG: إلغاء stoppingToken
BG-->>Svc: الخروج من الحلقة واكتمال StopAsync
Note over Svc,BG: إن تجاوز ShutdownTimeout الافتراضيّ 30 ثانية يُفرَض الإيقاف دون انتظار اكتمال التنظيف
Svc-->>SCM: تقرير التوقّف SERVICE_STOPPED
تنفيذ هذا الذهاب والإياب هو تطوير الخدمة في أصله، لكن في .NET تتولّاه دورة حياة الخدمة التي يدخلها AddWindowsService (الفصل 4). ما نكتبه نحن هو محتوى ExecuteAsync والاستجابة لطلب الإيقاف (الفصل 7) فقط.
3.2 عزل Session 0 ── الخدمة لا تستطيع عرض واجهة مستخدم
ابتداءً من Windows Vista تعمل الخدمات في جلسة معزولة اسمها Session 0، ولا يمكنها التفاعل مباشرة مع المستخدم.1 استدعاء MessageBox.Show أو عرض نموذج داخل الخدمة لا يُظهر شيئاً على شاشة المستخدم المسجَّل دخوله. بل يصبح سبب تعليق كلاسيكيّاً: تنتظر المعالجة زرّ موافقة لا يستطيع أحد ضغطه. عند نقل شيفرة قديمة إلى خدمة، تأكّد دائماً من عدم بقاء مربّعات حوار كانت مقصودة لعرض الأخطاء.
لماذا انفصلت الجلسات، وأيّ جلسة تدخل عند الاتّصال بـ RDP، وهل يمكن للكائنات المسمّاة عبور الجلسات ── آليّة الجلسات نفسها عالجناها في «كيف تفهم عزل الجلسات في Windows». ما يحتاجه هذا المقال نقطة واحدة: «الخدمة لا تعرض واجهة»، فاقرأ ما يلي على هذا الافتراض.
الحلّ الصحيح عند الحاجة إلى واجهة هو تكوين يفصل الخدمة (Session 0) عن تطبيق الواجهة (جلسة المستخدم) ويتخاطبان عبر الاتّصال بين العمليّات (IPC). هذا تصميم ترشد إليه Microsoft نفسها: يُستخدَم IPC مثل الأنابيب المسمّاة، ويعيد جانب الواجهة النتيجة إلى الخدمة.1 اختيار وسيلة IPC مرتَّب في المقال الشقيق المنشور في اليوم نفسه «جدول قرار الاتّصال بين العمليّات». وإن وُضع تطبيق الواجهة أيضاً على Generic Host، اصطفّ بناء DI والسجلّ والإعدادات في العمليّتين (راجع «استخدام Generic Host وBackgroundService في تطبيق سطح المكتب»).
4. طريقة الإنشاء في .NET ── Worker Service وAddWindowsService
4.1 القالب وProgram.cs
تطوير الخدمة في .NET يبدأ من قالب Worker Service. مضمَّن في SDK فيُنشئ هيكلاً بـ dotnet new worker، وتكفي إضافة حزمة Microsoft.Extensions.Hosting.WindowsServices واستدعاء AddWindowsService لتجهيز العمل كخدمة Windows.2 آليّة Generic Host التي يقوم عليها مشروحة في «ما هو .NET Generic Host».
using App.MonitorService;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Windowsサービスとして起動されたときにSCMと会話するライフタイムを組み込む。
// コンソールとして起動されたときは通常のConsoleLifetimeのまま動く
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "KsMonitor";
});
builder.Services.AddSingleton<MeasurementQueue>();
builder.Services.AddHostedService<MonitorWorker>();
IHost host = builder.Build();
host.Run();
في المشاريع ذات الأسلوب التقليديّ الذي يستخدم Host.CreateDefaultBuilder تُستدعى بدل ذلك UseWindowsService() كامتداد لـ IHostBuilder. الدور واحد.
وهناك مطبّ من النوع نفسه لمشكلة «البدء (اختياريّ)» في مقال Task Scheduler. الدليل الحاليّ عند التشغيل كخدمة هو C:\Windows\System32. إن قرأت appsettings.json ونظائره بافتراض مسار نسبيّ صرت في حالة «يعمل في سطر الأوامر ولا تُقرأ الإعدادات كخدمة». حلّ ملفّات الإعدادات نسبة إلى الملفّ التنفيذيّ، أو مرِّر --contentRoot في binpath عند التسجيل لتوضيح جذر المحتوى كما يرشد الدرس الرسميّ.2
4.2 ExecuteAsync ── تصميم stoppingToken والاستثناءات
الجسم يُكتَب في ExecuteAsync الموروث من BackgroundService. ما ينبغي حسمه هنا ينحصر في اثنين: «الاستجابة لطلب الإيقاف» و«كيف تُعامل الاستثناءات».
namespace App.MonitorService;
public sealed class MonitorWorker(
MeasurementQueue queue,
ILogger<MonitorWorker> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
// اسحب عنصراً واحداً من الطابور وعالجه. مرِّر الرمز حتماً حتى إلى الانتظار
var item = await queue.DequeueAsync(stoppingToken);
await ProcessAsync(item, stoppingToken);
}
catch (Exception ex) when (ex is IOException or TimeoutException)
{
// فشل يجوز الاستمرار بعده: سجِّله ثم أعد المحاولة بعد فاصل زمني
logger.LogError(ex, "فشل المعالجة. ستُعاد المحاولة بعد 30 ثانية.");
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
}
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
// طلب إيقاف من SCM. مسار طبيعي فلا نفعل شيئاً.
// تقييد when بكون السبب stoppingToken يمنع اعتبار إلغاء رماه
// مهلة داخلية أو نحوها «إيقافاً طبيعياً»، فيتوقّف العامل بهدوء
// ويبقى المضيف حيّاً
}
catch (Exception ex)
{
// فشل غير متوقَّع: StopHost الافتراضي يوقف المضيف «بنجاح»،
// فلا تُفعَّل خيارات استرداد SCM (إعادة التشغيل التلقائي).
// أنهِ برمز خروج غير صفري ليُبلَّغ SCM بأنّه «فشل»
logger.LogCritical(ex, "خطأ غير قابل للتعافي، لذا ستُنهى الخدمة.");
Environment.Exit(1);
}
}
private Task ProcessAsync(Measurement item, CancellationToken token)
=> throw new NotImplementedException();
}
- مرِّر
stoppingTokenإلى كلّ انتظار.Task.Delay، والإدخال/الإخراج، وانتظار الطابور. انتظار طويل يتجاهل الرمز في موضع واحد يصبح مرتع «خدمة لا تستجيب للإيقاف» (الفصل 7). - افصل الفشل القابل للاستمرار عن الفشل غير القابل للاسترداد. انقطاع الشبكة أو المهلة المؤقّتة تُلتقَط داخل الحلقة وتُسجَّل ويُعاد المحاولة.
catch (Exception)الذي يبتلع ويكمل فقط يصنع خدمة تدور في فراغ بهدوء. فكرة التصنيف مرتَّبة في «جدول قرار الإنهاء أو الاستمرار عند استثناء غير متوقَّع». - اعرف السلوك الافتراضيّ للاستثناء غير المعالَج. قبل .NET 6 كانت الاستثناءات المتسرّبة من
ExecuteAsyncتختفي في الظلام، فتبدو الخدمة تعمل ولا تفعل شيئاً («زومبي»). من .NET 6 صار الافتراضيّBackgroundServiceExceptionBehavior.StopHost، فيُسجَّل الاستثناء في السجلّ ويتوقّف المضيف.3 غير أنّ هذا الإيقاف «إيقاف طبيعيّ»، فلا تُعاد التشغيل ولو ضُبط خيار الاسترداد. الفشل الذي تريد استرداده بخيار الاسترداد تُنهيه صراحة إنهاءً غير طبيعيّ بـEnvironment.Exit(1)كما في الشيفرة أعلاه، وهذا أدب الدرس الرسميّ.2
4.3 يمكن تشغيله كوحدة تحكّم كما هو ── السبب الأكبر لسهولة التطوير
لا يبدّل AddWindowsService إلى دورة حياة الخدمة إلّا عند التشغيل كخدمة Windows. أي أنّ الملفّ التنفيذيّ نفسه يعمل كتطبيق سطر أوامر عاديّ عند F5 في Visual Studio أو dotnet run. تنغرس نقاط التوقّف، وضغط Ctrl+C يتيح التحقّق محلّيّاً من مسار StopAsync انطلاقاً من طلب الإيقاف.
غير أنّ «عمل في سطر الأوامر فلا يعمل كخدمة» لا يلزم. اختلاف حساب التنفيذ (الفصل 6)، وSession 0، والدليل الحاليّ ── هذه الثلاث وحدها تحتاج تأكيداً كخدمة على جهاز حقيقيّ. سبب «يعمل في سطر الأوامر ولا يعمل كخدمة» ينحصر تقريباً في هذه الثلاث.
5. التسجيل والتشغيل ── sc.exe وخيار الاسترداد وسجلّ الأحداث
5.1 التسجيل عبر sc.exe create
سجِّل الملفّ التنفيذيّ الصادر (dotnet publish، والإصدار كملفّ واحد أسهل تعاملاً) في SCM بـ sc.exe create. نفِّذ في PowerShell بصلاحيّات مدير.
sc.exe create "KsMonitor" binpath= "C:\Services\KsMonitor\KsMonitor.exe" start= delayed-auto obj= "NT AUTHORITY\LocalService" displayname= "خدمة KS لاستيراد بيانات القياس"
sc.exe description "KsMonitor" "خدمة مقيمة تستورد بيانات القياس وتسجّلها في DB (المسؤول: قسم نظم المعلومات)"
نذكر مطبّاً كلاسيكيّاً أوّلاً. بعد علامة المساواة في binpath= وstart= تلزم مسافة. اسم الخيار يمتدّ إلى المساواة، والمسافة بينه وبين القيمة واجبة في نحو sc.exe (حذفها يفشل).4 وافتراضيّ حذف obj= هو LocalSystem.4 التسجيل بلا تفكير يبدأ بأقوى صلاحيّة، فاحسم اختيار الفصل 6 عند التسجيل.
ضبط description أهمّ ممّا يبدو. إبقاء معلومة تمكّن من يفتح services.msc بعد سنوات من الحكم «ما هذه الخدمة، هل يجوز إيقافها، ممّن أسأل» يُسقط تكلفة التحقيق لاحقاً. الحذف بعد الإيقاف بـ sc.exe delete "KsMonitor".2
إن تعدّدت أجهزة التوزيع أو تكرّر التحديث (استبدال الملفّ) بانتظام، فمِل مبكّراً إلى تكوين يتولّى التسجيل والتحديث والحذف معاً عبر مثبِّت (مثل ServiceInstall في MSI / WiX) بدل العمل اليدويّ بـ sc.exe. دليل التسجيل اليدويّ يولّد حتماً جهازاً أسقط خطوة.
5.2 خيار الاسترداد ── اترك «إعادة التشغيل عند السقوط» لـ SCM
مزيّة كبيرة للتحويل إلى خدمة هي خيار الاسترداد المعياريّ في SCM. يمكن إعلان السلوك عند إنهاء العمليّة إنهاءً غير طبيعيّ بشكل تصريحيّ.2
sc.exe failure "KsMonitor" reset= 86400 actions= restart/60000/restart/60000/restart/300000
هذا المثال «الفشل الأوّل والثاني إعادة تشغيل بعد 60 ثانية، ومن الثالث فصاعداً بعد 5 دقائق، وعداد الفشل يُصفَّر بعد 24 ساعة». يمكن الضبط نفسه من الواجهة (خصائص services.msc ← تبويب «Recovery»). قبل بناء «مهمّة حراسة» أو سكربت مراقبة ذاتيّين، استخدم هذه الوظيفة المعياريّة أوّلاً.
تنبيهان فقط. الأوّل: كما في الفصل السابق لا يُفعَّل ما لم تنتهِ العمليّة برمز غير صفريّ. الإيقاف الطبيعيّ عبر StopHost خارج نطاق الاسترداد. الثاني: حالة تسقط حتماً فور البدء (خطأ إعداد، قاعدة بيانات غير واصلة) تصير حلقة إعادة تشغيل. إطالة الفاصل من المرّة الثالثة لهذا السبب، ومعه اصنع أوّلاً حالة يبقى فيها «لماذا سقطت» في سجلّ الأحداث (القسم التالي).
5.3 استخدام سجلّ الأحداث وسجلّ الملفّات معاً
يضيف Host.CreateApplicationBuilder على Windows موفّر مسجِّل EventLog تلقائيّاً. وما يصل إلى سجلّ الأحداث افتراضيّاً هو Warning فما فوق فقط.2 كثيراً ما يقع الالتباس «بعد التحويل إلى خدمة اختفت سجلات Information كلّها»، لكنّها لم تختفِ بل علقت في مرشّح EventLog الافتراضيّ. إن أردت أيضاً تسجيل أحداث تشغيل مثل البدء والإيقاف، فصرِّح بمستوى موفّر EventLog في appsettings.json.
{
"Logging": {
"EventLog": {
"SourceName": "KsMonitor",
"LogLevel": {
"Default": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
}
تنبيه واحد. مصدر الحدث لا يُكتَب إليه ما لم يُسجَّل مسبقاً، والتسجيل يحتاج امتيازات مدير. حذف SourceName لا ينجيك ── افتراضيّ AddWindowsService يجعل اسم التطبيق اسم المصدر2، فتبدأ على أيّ حال من «مصدر غير مسجَّل». حساب بأدنى صلاحيّة مثل LocalService لا يستطيع إنشاء المصدر وقت التشغيل، فإن فشل الإنشاء بدأ التشغيل بلا شيء في سجلّ الأحداث. أنجز التسجيل في جانب المثبِّت (أو معالجة إعداد بامتيازات مدير). القصّة نفسها التي كتبناها في الفصل 6 من مقال Task Scheduler: «افصل CreateEventSource إلى جانب الإعداد».
معيار الفصل: سجلّ الأحداث لـ«ما ينبغي أن يراه المشغّل» فقط (بدء، إيقاف، فشل، استرداد)، وتتبع تفاصيل المعالجة في سجلّ ملفّات ذاتيّ. الحدّ الأدنى لامتلاك سجلّ ملفّات ذاتيّ (التدوير، السلوك عند فشل الكتابة) في «الحدّ الأدنى لمتطلّبات مسجِّل ذاتيّ»، وتصميم إبقاء الأدلّة عند سقوط العمليّة في «تصميم إبقاء السجلّ والنسخة عند الانهيار». في تكوين يعيد التشغيل تلقائيّاً بخيار الاسترداد، بقاء سجلّ لحظة السقوط في موضعه هو الخيط الوحيد.
5.4 التحقّق من نجاح التسجيل ── أين تنظر في الأمر وفي الواجهة
بعد التسجيل انظر المواضع الثلاثة التالية بالترتيب وتأكّد أنّها «تعمل بالتكوين المقصود وبالحساب المقصود».
تأكيد التكوين (أمر). sc.exe qc "KsMonitor" يخرج محتوى التسجيل. ما ينبغي النظر إليه ثلاثة أسطر: BINARY_PATH_NAME (هل يشير إلى exe مكان الإصدار)، وSTART_TYPE (تلقائيّ أم متأخّر أم يدويّ)، وSERVICE_START_NAME (هل حساب التنفيذ ما حُسم في الفصل 6). حالة التشغيل في STATE من sc.exe query "KsMonitor"، أو في PowerShell Get-Service KsMonitor. القيمة الحاليّة لخيار الاسترداد تُقرأ بـ sc.exe qfailure "KsMonitor".
تأكيد التكوين (واجهة). Windows+R ← «services.msc» يفتح «Services» (الشاشة نفسها من «Computer Management» ← «Services and Applications» ← «Services»). انقر الخدمة باليمين ← «Properties»: تبويب «General» لنوع بدء التشغيل والنصّ الوصفيّ المضبوط في 5.1، وتبويب «Log On» لحساب التنفيذ، وتبويب «Recovery» لسلوك الفشل الأوّل والثاني وما بعده.
تأكيد سجلّ الأحداث. Windows+R ← «eventvwr.msc» يفتح عارض الأحداث، وانظر أحداث المصدر «Service Control Manager» في «Windows Logs» ← «System». يبقى هنا الحدث 7000 / 7011 عندما لا يلحق تقرير اكتمال البدء7، والحدث 7031 عند إنهاء الخدمة إنهاءً غير طبيعيّ (إن رافقه سلوك استرداد) و7034 (إن لم يرافقه).8 أمّا سجلّ التطبيق نفسه الذي ضبطت مستواه في 5.3 فوجهة موفّر EventLog افتراضيّاً «Application»9، لذا صفِّ «Windows Logs» ← «Application» باسم المصدر (SourceName، والافتراضيّ اسم التطبيق2). احفظ أنّ حياة الخدمة وموتها في «System»، ومحتوى التطبيق في «Application» فلا تبحث طويلاً عند العطل.
6. حساب التنفيذ ── لا تختر LocalSystem بدافع الكسل
تعمل الخدمة في سياق أمان الحساب المحدَّد، ويسجِّل SCM الدخول بذلك الحساب عند البدء ويلحق رمزاً بالعمليّة.10 هذه نسخة الخدمة من حديث «بمن تُنفَّذ» في الفصل 3 من مقال Task Scheduler. نرتّب الخيارات.
| الحساب | الصلاحيّات | الهويّة على الشبكة | إدارة كلمة المرور | موضع الاستخدام |
|---|---|---|---|---|
| LocalSystem | قويّة جدّاً (تعادل نظام التشغيل) | حساب الحاسوب | غير لازمة | تجنّبه مبدأً. انتبه لأنّه افتراضيّ sc.exe create |
| LocalService | الحدّ الأدنى | مجهول (لا وصول إلى المشاركات) | غير لازمة | الخيار الأوّل للمعالجة المكتملة محلّيّاً |
| NetworkService | الحدّ الأدنى | حساب الحاسوب | غير لازمة | معالجة خفيفة تلمس موارد داخل النطاق |
| حساب افتراضيّ (NT SERVICE\اسم الخدمة) | بالقدر الممنوح | حساب الحاسوب | غير لازمة | يمكن منح ACL لكلّ خدمة. أدنى صلاحيّة لموارد محلّيّة |
| gMSA | بالقدر الممنوح | gMSA نفسه | المتحكّم بالنطاق يدير تلقائيّاً | الخيار الجادّ لخدمة تلمس مشاركة أو قاعدة بيانات في النطاق |
نقاط الحكم ثلاث.
- لا تختر LocalSystem لأنّ «الأمر يعمل». ثغرة الخدمة تصل مباشرة إلى الاستيلاء على الجهاز كلّه. هل تحتاج فعلاً صلاحيّة تعادل المدير؟ ترتيب «متى تلزم امتيازات المدير» يُستخدَم كما هو. في كثير من الحالات المطلوب «كتابة إلى مجلّد معيّن» فقط، ويكفي منح ACL المجلّد لحساب افتراضيّ (
NT SERVICE\KsMonitor). الحساب الافتراضيّ لا يحتاج إنشاء ولا إدارة كلمة مرور.5 - مطبّ المشاركة الشبكيّة. LocalService يصبح مجهولاً على الشبكة، فيفشل الوصول إلى
\\server\share. NetworkService والحساب الافتراضيّ وLocalSystem يخرجون إلى الشبكة كحساب حاسوب (DOMAIN\اسم_الجهاز$)5، فيلزم على جانب المشاركة الإذن لحساب الحاسوب في المشاركة وفي NTFS معاً. جوهر «أذِنّا للمستخدم لكن الخدمة وحدها لا تقرأ» غالباً هذا. احسم «بمن تخرج إلى الشبكة» أوّلاً ثمّ اضبط جانب المشاركة. - إن شغّلت بحساب مستخدم عاديّ، فمع تشغيل كلمة المرور. الحساب المخصّص يحتاج حقّ «Log on as a service»، وإن انتهت صلاحية كلمة المرور فشل تسجيل الدخول وتعذّر بدء الخدمة.10 هذه نسخة الخدمة من مشكلة «المهمّة تموت صامتة بتغيير كلمة المرور». في بيئة النطاق، الصواب محو المشكلة كلّها بـ gMSA الذي يدير النطاق كلمة المرور تلقائيّاً (الخلاصة نفسها في القسم 3.2 من مقال Task Scheduler).
7. الإيقاف الآمن ── ShutdownTimeout والمعالجة الجارية
نثبّت مسار الإيقاف. عندما يصدر SCM طلب إيقاف من services.msc أو sc.exe stop أو إيقاف تشغيل نظام التشغيل، تحوّله دورة حياة الخدمة في .NET إلى إيقاف المضيف (StopApplication)، فيُلغى stoppingToken، ويخرج ExecuteAsync، وتُستدعى StopAsync لكلّ خدمة. الزمن الذي ينتظر فيه المضيف سلسلة الإيقاف هذه هو HostOptions.ShutdownTimeout، والافتراضيّ 30 ثانية.611 إن لم تلحق فُرض الإيقاف دون انتظار اكتمال التنظيف.
إن لم تكفِ 30 ثانية لإنهاء العنصر الجاري، فمدِّد بالعدّ العكسيّ من الزمن.
builder.Services.Configure<HostOptions>(options =>
{
// 仕掛かり中の処理を書き切るのに必要な最大時間から逆算する
options.ShutdownTimeout = TimeSpan.FromSeconds(90);
});
بعد ذلك تصميم الإيقاف ثلاث نقاط.
- قرِّر ما يُفعل بعد طلب الإيقاف كترتيب. وقف قبول الجديد ← إكمال المعالجة الجارية (أو قطعها عند حدّ آمن وتسجيلها بشكل يمكن استئنافه) ← تنظيف الاتّصالات والملفّات المؤقّتة. بلا هذا الترتيب تقع في أحد طرفين: رمي الكلّ لحظة رؤية الرمز، أو محاولة إنهاء الكلّ فنفاد الوقت.
- لا تصنع «خدمة لا تستجيب للإيقاف». حلقة أو انتظار طويل يتجاهل الرمز في موضع واحد يكفي لتجميد الخدمة على SCM في حالة «Stopping». هذا يعيق إعادة تشغيل Windows Update ويطلب قتلاً يدويّاً عند كلّ إيقاف مخطَّط للخادم، وهو أكثر أعطال التشغيل كرهاً. كما في الفصل 4، افحص الرمز عند كلّ حدّ معالجة، ومرِّر
CancellationTokenإلى الإدخال/الإخراج الطويل. تشغيل سطر الأوامر يتيح تجربة مسار الإيقاف هذا كما هو بـ Ctrl+C، فيُستحسَن إدراج «كم ثانية من Ctrl+C إلى الإنهاء» بند اختبار قبل الإصدار. - قدِّم تصميماً لا ينكسر حتّى عند القتل على أناقة معالجة الإيقاف. انقطاع الكهرباء والإنهاء القسريّ يحدثان مهما أتقنت معالجة الإيقاف. المعاملات، وكتابة الملفّات الذرّيّة، ووحدات معالجة قابلة لإعادة التشغيل ── البناء الذي «يستقيم عند البدء التالي ولو مات في المنتصف» هو الجسم، ومعالجة الإيقاف الأنيقة مسألة أدب فحسب.
8. الخلاصة
الحكم بسيط. المعالجة الدوريّة لجدولة المهام، والانتظار الدائم والاستجابة بالثانية والاسترداد التلقائيّ لخدمة Windows، والواجهة كجوهر لتطبيق مقيم. إذا حسمت التحويل إلى خدمة، فالمسار المعياريّ الحاليّ شكل «طوِّر كسطر أوامر ووزِّع كخدمة» عبر Worker Service في .NET وAddWindowsService.
ما يُحسَم كتصميم عند التسجيل أربع نقاط: نوع البدء (خدمات الأعمال بدء متأخّر)، وحساب التنفيذ (تجنّب LocalSystem، حساب افتراضيّ أو gMSA)، وخيار الاسترداد (ثنائية sc.exe failure وEnvironment.Exit(1))، والإيقاف (ShutdownTimeout وتنظيف المعالجة الجارية). بهذه الأربع وكتابة ExecuteAsync التي تحترم stoppingToken لم تعد خدمة Windows «شيئاً صعباً صنعه على نحو خاصّ». وبالمقابل، الخدمة التي بدأت بلا حسم هذه الأربع تعود بعد سنوات بمعاناة ثلاثيّة: «لا تُوقَف، ولا يُلاحَظ سقوطها، وصلاحيّاتها أقوى من أن تُلمَس». وإعادة بناء خدمة قائمة أيضاً أقرب طريقها جرد هذه الأربع.
مقالات ذات صلة
- لماذا لا تُنفَّذ مهامّ Task Scheduler أو تنتهي بالرمز 0x1 ── تشخيص الأسباب وتصميم تشغيل آمن
- ما هو .NET Generic Host
- جدول قرار الاتّصال بين العمليّات
- تصميم إبقاء السجلّ والنسخة عند الانهيار
مجالات الاستشارة ذات الصلة
تتعامل شركة كومورا سوفت ذ.م.م. مع مراجعة تصميم المعالجة المقيمة (بما في ذلك حكم الانتقال من جدولة المهام)، واستشارات التحقيق وإعادة البناء لخدمات Windows من نوع «لا تستجيب للإيقاف» و«تسقط دون أن يُلاحَظ».
المراجع
-
Microsoft Learn, Interactive Services. حول أنّ الخدمات ابتداءً من Windows Vista لا تتفاعل مباشرة مع المستخدم، وأنّها تعمل في Session 0، وأنّ التصميم الموصى به عند الحاجة إلى واجهة هو التعاون عبر IPC مع تطبيق واجهة في عمليّة منفصلة. ↩ ↩2 ↩3
-
Microsoft Learn, Create Windows Service using BackgroundService. الدرس الرسميّ لتحويل Worker Service إلى خدمة Windows. حول
AddWindowsService، وكون افتراضيّ موفّر EventLog هو Warning، والتسجيل والاسترداد والحذف عبرsc.exe، واشتراط رمز خروج غير صفريّ لخيار الاسترداد. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 -
Microsoft Learn, .NET 6 breaking change: Exception handling in hosting. حول أنّ الاستثناء غير المعالَج في
BackgroundService.ExecuteAsyncابتداءً من .NET 6 يُسجَّل في السجلّ ثمّ يوقف المضيف افتراضيّاً (BackgroundServiceExceptionBehavior.StopHost). ↩ ↩2 -
Microsoft Learn, sc.exe create. حول مواصفات
start=(auto / demand / delayed-auto وغيرها) وobj=(الافتراضيّ LocalSystem)، ووجوب مسافة بعد علامة مساواة الخيار (حذفها يفشل). ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Service Accounts in Windows Server. حول أنّ الحساب الافتراضيّ (
NT SERVICE\اسم الخدمة) لا يحتاج إدارة كلمة مرور ويصل إلى الشبكة ببيانات اعتماد حساب الحاسوب، وأنّ النطاق يدير كلمة مرور gMSA تلقائيّاً. ↩ ↩2 ↩3 -
Microsoft Learn, .NET Generic Host. حول مسار معالجة إيقاف المضيف، والانتظار عند الإيقاف بمهلة إيقاف قابلة للضبط (الافتراضيّ 30 ثانية). ↩ ↩2
-
Microsoft Learn, A service does not start, and events 7000 and 7011 are logged. حول انتظار SCM بدء الخدمة للزمن المحدَّد في
ServicesPipeTimeoutوتسجيل الحدث 7000 / 7011 عند التجاوز، وإجراء رفع المهلة الافتراضيّة. ↩ ↩2 -
Microsoft Learn (أرشيف), Event ID 7031 — Service Stop Operations وEvent ID 7034 — Service Stop Operations. حول تسجيل SCM للإنهاء غير المتوقَّع للخدمة ولتعذّر إعادة التشغيل بعد سلوك الاسترداد، وكون رسالة الحدث 7031 (الاسم الرمزيّ
EVENT_SERVICE_CRASH) «انتهت الخدمة على نحو غير متوقَّع. هذه المرّة N. سيُنفَّذ إجراء التصحيح التالي بعد M ملي ثانية»، وكون 7034 (الاسم الرمزيّEVENT_SERVICE_CRASH_NO_ACTION) بلا وصف لإجراء التصحيح، وكون المصدر في كليهما Service Control Manager، وإمكان تغيير سلوك الاسترداد من تبويب «Recovery» في خصائص إضافة «Services». ↩ -
Microsoft Learn, EventLogSettings.LogName Property. حول أنّ اسم سجلّ الأحداث الذي يكتب إليه موفّر مسجِّل EventLog يصبح افتراضيّاً “Application” إن لم يُحدَّد. ↩
-
Microsoft Learn, Service User Accounts. حول عمل الخدمة في سياق أمان الحساب المحدَّد، وقيام SCM بتسجيل الدخول عند البدء وتعذّر بدء الخدمة إذا انتهت صلاحية كلمة المرور، والحسابات الخاصّة LocalService / NetworkService / LocalSystem. ↩ ↩2
-
Microsoft Learn, HostOptions.ShutdownTimeout Property. تعريف الخاصّيّة التي تتحكّم بالمهلة الافتراضيّة لـ
StopAsync. ↩
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
التاريخ والوقت والمناطق الزمنية في تطبيقات الأعمال ── من فخاخ DateTime إلى مبدأ التخزين بـ UTC وتصميم الاختبارات
ينزاح الوقت 9 ساعات بعد نقل الخادم. نرتّب أسباب أعطال التاريخ والوقت انطلاقاً من Kind في DateTime والتحويل الضمني. نشرح التمييز مع DateTi...
استخدام SQLite في تطبيقات C# للأعمال ── وضع WAL، والتحكّم الحصريّ، والوقاية من التلف، والتمييز عن EF Core
نرتّب هنا المعرفة العمليّة اللازمة لدمج SQLite في تطبيقات الأعمال عبر Microsoft.Data.Sqlite. نشرح وضع WAL، وSQLITE_BUSY وتوحيد مسار الكتا...
كيف تختار مكان حفظ بيانات تطبيق Windows محليّاً ── جدول قرار بين SQLite وJSON وRegistry وAccess
أين ينبغي حفظ بيانات تطبيق سطح مكتب Windows، وبأيّ صيغة؟ نرتّب الفرق بين AppData وProgramData، ونقاط قوّة وعيوب كلّ من SQLite وملفّات JSO...
التعديل الآمن على تطبيق أعمال قديم بلا اختبارات ── ممارسة اختبار التوصيف وإعادة الهيكلة
لإجراء تعديلات آمنة على تطبيق أعمال بلا اختبارات، نشرح خطوات اختبار التوصيف (أسلوب Golden Master) الذي يثبّت السلوك الحالي، وكيفيّة صنع ن...
إلى متى ستستمر تطبيقات VB6 في العمل ── وضع دعم بيئة التشغيل والمسار العملي للترحيل إلى .NET
إلى متى تستمر تطبيقات VB6 في العمل؟ نرتّب وضع بيئة التشغيل المشمولة حتى في Windows 11 وانتهاء دعم بيئة التطوير، وجدول القرار بين إعادة ال...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- كيف نميّز بين استخدام جدولة المهام وخدمة Windows؟
- إذا كانت المعالجة الدوريّة بفاصل زمنيّ لا يقلّ عن بضع دقائق، ولا تحتفظ بحالة بين مرّة وأخرى، فجدولة المهام كافية. أمّا إذا دخل ضمن المتطلّبات الانتظار الدائم عبر TCP أو الأنابيب، أو مراقبة مجلّد عبر FileSystemWatcher، أو الاستجابة بالثانية، أو الاسترداد التلقائيّ عند السقوط، فخدمة Windows هي الخيار. وإذا بدأتَ بتقطيع الاستقصاء عبر «مهمّة كلّ 5 دقائق»، فتلك إشارة إلى أنّك تُعيد تنفيذ عمليّة مقيمة بشكل متدهور. وإذا كانت واجهة المستخدم هي الجوهر (كالتحكّم من منطقة الإشعارات)، فالخيار الثالث هو تطبيق مقيم لا يعمل إلّا أثناء تسجيل الدخول.
- هل يمكن لخدمة Windows عرض واجهة مستخدم (شاشة)؟
- لا يمكن ذلك. ابتداءً من Windows Vista، تعمل الخدمات ضمن جلسة معزولة تُسمّى Session 0، ولا يمكنها التفاعل مباشرةً مع المستخدم. استدعاء MessageBox.Show داخل الخدمة لا يُظهِر شيئاً على شاشة المستخدم، بل يتحوّل إلى سبب تعليق حيث تتوقّف المعالجة منتظرةً زرّ موافقة لا يستطيع أحد الضغط عليه. الحلّ الصحيح عند الحاجة إلى واجهة مستخدم هو فصل العمليّة إلى خدمة وتطبيق واجهة يتخاطبان عبر الاتّصال بين العمليّات كالأنابيب المسمّاة. عند نقل شيفرة قديمة إلى خدمة، تأكّد دائماً من عدم بقاء مربّعات حوار كانت مخصّصة لعرض الأخطاء.
- كيف نُنشئ خدمة Windows في .NET؟
- الطريقة الرسميّة هي البدء من قالب Worker Service (dotnet new worker)، ثمّ إضافة حزمة Microsoft.Extensions.Hosting.WindowsServices واستدعاء AddWindowsService. وبما أنّ الملفّ التنفيذيّ نفسه يعمل كتطبيق سطر أوامر عاديّ عند التشغيل عبر F5 في Visual Studio أو dotnet run، يصبح التطوير والتصحيح أسهل بكثير. يتمّ التسجيل عبر sc.exe create، لكن يجب الانتباه إلى المواصفة الخاصّة التي تتطلّب مسافة بعد علامة المساواة في binpath= وstart=، وإلى أنّ حذف obj= يجعل الإعداد الافتراضيّ LocalSystem (أقوى صلاحيّة). والدليل الحاليّ عند بدء الخدمة هو C:\Windows\System32، لذا يُحلّ ملفّ الإعدادات بناءً على مسار الملفّ التنفيذيّ.
- ماذا يحدث للخدمة عند وقوع استثناء في BackgroundService؟
- ابتداءً من .NET 6، الاستثناء غير المُعالَج المتسرّب من ExecuteAsync يُسجَّل في السجلّ ثمّ يوقِف المضيف بالإعداد الافتراضيّ (BackgroundServiceExceptionBehavior.StopHost). لكن بما أنّ هذا يُعامَل «إيقافاً طبيعيّاً»، فلا يُفعَّل خيار الاسترداد الخاصّ بـ SCM (إعادة التشغيل التلقائيّة). الفشل الذي تريد أن يستعيد فيه خيار الاسترداد الخدمة يجب إسقاط العمليّة صراحةً بخروج غير طبيعيّ ورمز غير صفريّ، كما في Environment.Exit(1). أمّا الفشل القابل للاستمرار كانقطاع الشبكة، فيُلتقَط داخل الحلقة ويُسجَّل ويُعاد المحاولة، مع تصميم يميّزه عن الفشل غير القابل للاسترداد.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.