الكيانات الدائمة

مهم

سينتهي الدعم للنموذج قيد التنفيذ في 10 نوفمبر 2026. نوصي بشدة بترحيل تطبيقاتك إلى نموذج العامل المعزول للحصول على الدعم الكامل.

تعرف دوال الكيانات عمليات تقرأ وتحدث أجزاء صغيرة من الحالة، وتسمى الكيانات الدائمة. مثل وظائف المنسق، تستخدم وظائف الكيان نوعا خاصا يسمى محفز الكيان. على عكس وظائف المنسق، تدير دوال الكيان حالة الكيان بشكل صريح بدلا من تمثيل الحالة من خلال تدفق التحكم. تساعدك الكيانات على توسيع نطاق التطبيقات من خلال توزيع العمل على عدة كيانات، كل منها بحالة متواضعة.

الكيانات تعرف عمليات تقرأ وتحدث أجزاء صغيرة من الحالة، وتسمى الكيانات الدائمة. على عكس المنسقين، تدير الكيانات الحالة بشكل صريح بدلا من تمثيل الحالة من خلال تدفق التحكم. تساعدك الكيانات على توسيع نطاق التطبيقات من خلال توزيع العمل على عدة كيانات، كل منها بحالة متواضعة.

دعم الكيانات الدائمة

تتوفر وظائف الكيان والميزات ذات الصلة بنسخ Durable Functions 2.0 وما بعدها.

لغة البرمجة دعم الكيانات الدائمة
.NET معزول
.NET قيد المعالجة
Java
Python
JavaScript
PowerShell
مجموعة تطوير المهام المتينة دعم الكيانات الدائمة
.NET معزول
.NET قيد المعالجة
Java
Python
JavaScript
PowerShell

المفاهيم العامة للكيانات الدائمة

الكيانات تتصرف كخدمات صغيرة تتواصل عبر الرسائل. لكل كيان هوية فريدة، وإذا لزم الأمر، حالة داخلية. تشغل الكيانات العمليات عند طلب الطلب. قد تقوم العملية بتحديث الحالة، أو تتصل بخدمات خارجية، أو تنتظر الرد. تتواصل الكيانات مع الكيانات الأخرى، والتنسيقات، والعملاء من خلال رسائل ترسلها وقت التشغيل عبر قوائم انتظار موثوقة.

لمنع النزاعات، يدير كيان واحد العمليات بشكل تسلسلي، واحدة تلو الأخرى.

ملحوظة

عندما تستدعي كيانا، يقوم بمعالجة الحمولة حتى اكتمالها، ثم يحدد جدولة تنفيذ جديد يتم تفعيله عند وصول إدخال جديد. وبالتالي، قد تظهر سجلات تنفيذ الكيانات لديك تنفيذا إضافيا بعد كل استدعاء. هذا متوقع.

معرف الكيان

استخدم معرف الكيان للوصول إلى كيان معين. معرف الكيان هو زوج من السلاسل النصية التي تحدد بشكل فريد نسخة الكيان. يتكون من:

  • اسم الكيان، الذي يحدد نوع الكيان. على سبيل المثال، Counter. هذا الاسم يطابق اسم دالة الكيان التي تنفذ الكيان. الأمر ليس حساسا لعلامات الحروف.
  • مفتاح الكيان، الذي يحدد الكيان بشكل فريد بين جميع الكيانات الأخرى التي تحمل نفس الاسم. على سبيل المثال، واجهة مستخدم (GUID).

على سبيل المثال، Counter قد تستخدم وظيفة الكيان لتسجيل النقاط في لعبة عبر الإنترنت. كل نسخة من اللعبة لها معرف كيان فريد، مثل @Counter@Game1 و @Counter@Game2. لاستهداف كيان ما، حدد معرف الكيان الخاص به.

عمليات الكيان

لاستدعاء عملية على كيان، حدد:

  • معرف الكيان للكيان المستهدف.
  • اسم العملية، وهو سلسلة تحدد العملية التي يجب تنفيذها. على سبيل المثال، يمكن للكيان Counter دعم add، get، أو reset العمليات.
  • إدخال العمليات، وهو معامل اختياري للعملية. على سبيل المثال، تأخذ العملية add عددا صحيحا كمدخل.
  • الوقت المجدول، وهو معلمة اختيارية لتحديد وقت تسليم العملية. على سبيل المثال، جدولة عملية لتجرى بعد عدة أيام.

يمكن للعمليات أن ترجع قيمة نتيجة أو نتيجة خطأ، مثل خطأ جافاسكريبت أو استثناء .NET. التوزيع الموسيقي المستدعي يتلقى النتيجة أو الخطأ.

يمكن للعمليات أن ترجع قيمة نتيجة أو نتيجة خطأ، مثل استثناء .NET أو استثناء Python. يتلقى المتصل النتيجة أو الخطأ.

يمكن لعملية الكيان أيضًا إنشاء حالة الكيان وقراءتها وتحديثها وحذفها. يستمر وقت التشغيل دائما في حالة الكيان في التخزين.

تعريف الكيانات

استخدم إحدى واجهات برمجة التطبيقات (API) لتعريف الكيانات في .NET:

بناء الصياغة المعتمد على الوظائف: في بناء الجملة القائم على الوظائف، تكتب كل كيان كدالة وترسل العمليات في تطبيقك. تعمل هذه الصياغة بشكل جيد للكيانات ذات الحالة البسيطة، أو العمليات القليلة، أو مجموعة العمليات الديناميكية، كما في أطر التطبيقات. لكن قد يكون صيانته متعبا لأنه لا يكتشف أخطاء النوع أثناء وقت الترجمة.

النحو القائم على الفئة: في بناء الجملة المعتمد على الفئة، تقوم .NET الفئات والطرق بنمذجة الكيانات والعمليات. هذا البناء الصيغي يجعل الكود أسهل في القراءة ويسمح لك باستدعاء العمليات بطريقة آمنة للنوع. إنها طبقة رقيقة فوق بناء الجملة المعتمدة على الوظائف، لذا يمكنك خلط النسختين في نفس التطبيق.

واجهات برمجة التطبيقات التي تستخدمها تعتمد على مكان تشغيل دوال C# الخاصة بك. يوصى بعملية عامل معزولة ، لكن يمكنك أيضا تشغيلها في عملية المضيف.

مثال قائم على وظيفة العملية المعزولة للعامل

المثال التالي يظهر كيانا قائما Counter على الوظائف في عملية عامل معزولة. يدعم add، reset، get، و delete.

[Function(nameof(Counter))]
public static Task Counter([EntityTrigger] TaskEntityDispatcher dispatcher)
{
    return dispatcher.DispatchAsync(operation =>
    {
        if (operation.State.GetState(typeof(int)) is null)
        {
            operation.State.SetState(0);
        }

        switch (operation.Name.ToLowerInvariant())
        {
            case "add":
                int state = operation.State.GetState<int>();
                state += operation.GetInput<int>();
                operation.State.SetState(state);
                return new(state);
            case "reset":
                operation.State.SetState(0);
                break;
            case "get":
                return new(operation.State.GetState<int>());
            case "delete":
                operation.State.SetState(null);
                break;
        }

        return default;
    });
}

مثال على عملية العامل المعزولة القائمة على الطبقة

المثال التالي يوضح تنفيذ الكيان Counter باستخدام الفئات والطرق.

public class Counter : TaskEntity<int>
{
    readonly ILogger logger;

    public Counter(ILogger<Counter> logger)
    {
        this.logger = logger;
    }

    public void Add(int amount) => this.State += amount;

    public void Reset() => this.State = 0;

    public int Get() => this.State;

    [Function(nameof(Counter))]
    public Task RunEntityAsync([EntityTrigger] TaskEntityDispatcher dispatcher)
    {
        return dispatcher.DispatchAsync(this);
    }
}

مثال قائم على الوظائف داخل العملية

يظهر هذا المثال كيانا بسيطا Counter تم تنفيذه كدالة دائمة. تعرف ثلاث عمليات —add ، reset، و get—تستخدم حالة صحيحة.

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            ctx.SetState(ctx.GetState<int>() + ctx.GetInput<int>());
            break;
        case "reset":
            ctx.SetState(0);
            break;
        case "get":
            ctx.Return(ctx.GetState<int>());
            break;
    }
}

لمزيد من المعلومات، انظر بناء الجملة القائم على الوظائف.


مثال قائم على الفئة أثناء العملية

يظهر هذا المثال نفس Counter الكيان المنفذ باستخدام الفئات والطرق.

[JsonObject(MemberSerialization.OptIn)]
public class Counter
{
    [JsonProperty("value")]
    public int CurrentValue { get; set; }

    public void Add(int amount) => this.CurrentValue += amount;

    public void Reset() => this.CurrentValue = 0;

    public int Get() => this.CurrentValue;

    [FunctionName(nameof(Counter))]
    public static Task Run([EntityTrigger] IDurableEntityContext ctx)
        => ctx.DispatchAsync<Counter>();
}

هذا الكيان يخزن الحالة في Counter كائن يحمل القيمة العدادية الحالية. يقوم Durable Functions بتسلسل هذا الكائن وإزالة التسلسل باستخدام مكتبة Json.NET.

لمزيد من المعلومات، راجع تعريف فئات الكيانات.

يدعم مجموعة تطوير المهام الدائمة ل .NET تعريف الكيانات باستخدام بناء جملة قائم على الفئة. نفذ الفئة TaskEntity<TState> الأساسية لتعريف كيانك.

المثال التالي يظهر كيانا Counter تم تنفيذه باستخدام مجموعة تطوير المهام الدائمة:

using Microsoft.DurableTask.Entities;

public class Counter : TaskEntity<int>
{
    public void Add(int amount) => this.State += amount;

    public void Reset() => this.State = 0;

    public int Get() => this.State;
}

لتسجيل الكيان لدى العامل:

builder.Services.AddDurableTaskWorker()
    .AddTasks(registry =>
    {
        registry.AddEntity<Counter>();
    })
    .UseDurableTaskScheduler(connectionString);

لإرسال إشارة أو استدعاء كيان من المنسق:

public class EntityOrchestration : TaskOrchestrator<string, int>
{
    public override async Task<int> RunAsync(TaskOrchestrationContext context, string entityKey)
    {
        var entityId = new EntityInstanceId(nameof(Counter), entityKey);

        // Signal the entity (fire-and-forget)
        await context.Entities.SignalEntityAsync(entityId, nameof(Counter.Add), 1);

        // Call the entity and wait for response
        int currentValue = await context.Entities.CallEntityAsync<int>(entityId, nameof(Counter.Get));

        return currentValue;
    }
}

الوصول إلى الكيانات

الوصول إلى الكيانات باستخدام الاتصال أحادي الاتجاه أو الاتجاهين:

  • الاتصال بكيان يستخدم الاتصال ذهابا وإيابا (ذهابا وإيابا). أرسل رسالة عملية إلى الكيان، ثم انتظر رسالة الرد قبل أن تتابع. توفر رسالة الاستجابة قيمة نتيجة أو خطأ (على سبيل المثال، خطأ جافا سكريبت أو استثناء .NET).
  • الإشارة إلى كيان تستخدم اتصالا أحادي الاتجاه (إطلاق النار والنسيان). أرسل رسالة عملية لكن لا تنتظر الرد. وقت التشغيل يضمن التسليم، لكن المرسل لا يمكنه ملاحظة قيم النتائج أو الأخطاء.

الوصول إلى الكيانات من دوال العميل، أو وظائف المنسق، أو دوال الكيان. ليس كل السياق يدعم كلا نوعي التواصل:

  • تدعم وظائف العميل كيانات الإشارة وقراءة حالة الكيان.
  • تدعم وظائف التنسيق الكيانات التي ترسل إشارات واستدعاء.
  • تدعم وظائف الكيانات كيانات الإشارة.

الوصول إلى الكيانات باستخدام الاتصال أحادي الاتجاه أو الاتجاهين:

  • الاتصال بكيان يستخدم الاتصال ذهابا وإيابا (ذهابا وإيابا). أرسل رسالة عملية إلى الكيان، ثم انتظر رسالة الرد قبل أن تتابع. رسالة الرد توفر قيمة نتيجة أو خطأ.
  • الإشارة إلى كيان تستخدم اتصالا أحادي الاتجاه (إطلاق النار والنسيان). أرسل رسالة عملية لكن لا تنتظر الرد. وقت التشغيل يضمن التسليم، لكن المرسل لا يمكنه ملاحظة قيم النتائج أو الأخطاء.

الوصول إلى الكيانات من العملاء أو المنسقين. ليس كل السياق يدعم كلا نوعي التواصل:

  • يدعم العملاء الكيانات الإشارة وقراءة حالة الكيان.
  • يدعم المنسقون كيانات الإشارة والاتصال بها.

توضح الأمثلة التالية كيفية الوصول إلى الكيانات.

مثال: العميل يرسل إشارات إلى كيان

للوصول إلى الكيانات من دالة Azure عادية، والتي تعرف أيضا باسم دالة العميل، استخدم entity client binding. المثال التالي يظهر دالة يتم تفعيلها في قائمة انتظار ترسل إشارة إلى كيان باستخدام هذا الربط.

ملحوظة

وللتبسيط، تظهر الأمثلة التالية بناء الجملة المكتوب بصورة واسعة بغرض الوصول إلى الكيانات. بشكل عام، تصل إلى الكيانات عبر الواجهات لأنها توفر المزيد من التحقق من الأنواع.

قيد العملية:

قيد العملية:

[FunctionName("AddFromQueue")]
public static Task Run(
    [QueueTrigger("durable-function-trigger")] string input,
    [DurableClient] IDurableEntityClient client)
{
    // Entity operation input comes from the queue message content.
    var entityId = new EntityId(nameof(Counter), "myCounter");
    int amount = int.Parse(input);
    return client.SignalEntityAsync(entityId, "Add", amount);
}

عملية العامل المعزولة:

[Function("AddFromQueue")]
public static Task Run(
    [QueueTrigger("durable-function-trigger")] string input,
    [DurableClient] DurableTaskClient client)
{
    // Entity operation input comes from the queue message content.
    var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
    int amount = int.Parse(input);
    return client.Entities.SignalEntityAsync(entityId, "Add", amount);
}

مصطلح الإشارة يعني أن استدعاء واجهة برمجة تطبيقات الكيان هو استدعاء أحادي الاتجاه وغير متزامن. لا يمكن لوظيفة العميل معرفة متى يعالج الكيان العملية. لا يمكن لوظيفة العميل ملاحظة قيم النتائج أو الاستثناءات.

للوصول إلى الكيانات من عميل، استخدم DurableTaskClient حالة الكيان للإشارة أو القراءة.

// Signal an entity
var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
await client.Entities.SignalEntityAsync(entityId, nameof(Counter.Add), 1);

مصطلح الإشارة يعني أن استدعاء واجهة برمجة تطبيقات الكيان هو استدعاء أحادي الاتجاه وغير متزامن. لا يمكن للعميل أن يعرف متى يعالج الكيان العملية.

مثال: العميل يقرأ حالة كيان

استعلام حالة كيان من دالة عميل:

قيد العملية:

[FunctionName("QueryCounter")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function)] HttpRequestMessage req,
    [DurableClient] IDurableEntityClient client)
{
    var entityId = new EntityId(nameof(Counter), "myCounter");
    EntityStateResponse<JObject> stateResponse = await client.ReadEntityStateAsync<JObject>(entityId);
    return req.CreateResponse(HttpStatusCode.OK, stateResponse.EntityState);
}

عملية العامل المعزولة:

[Function("QueryCounter")]
public static async Task<HttpResponseData> Run(
    [HttpTrigger(AuthorizationLevel.Function)] HttpRequestData req,
    [DurableClient] DurableTaskClient client)
{
    var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
    EntityMetadata<int>? entity = await client.Entities.GetEntityAsync<int>(entityId);

    if (entity is null)
    {
        return req.CreateResponse(HttpStatusCode.NotFound);
    }

    HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
    await response.WriteAsJsonAsync(entity);

    return response;
}

يمكن للعملاء الاستعلام عن حالة الكيان:

var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
EntityMetadata<int>? entity = await client.Entities.GetEntityAsync<int>(entityId);

if (entity != null)
{
    Console.WriteLine($"Current value: {entity.State}");
}

تذهب استفسارات حالة الكيان إلى مخزن التتبع الدائم وتعيد الحالة الدائمة للكيان التي استمر في الحالة الأخيرة. هذه الحالة دائما ما تكون حالة "ملتزمة"، لذا فهي ليست حالة وسيطة مؤقتة تفترض أثناء تنفيذ العملية. لكن هذه الحالة قد تكون مملكة مقارنة بحالة الكيان في الذاكرة. ولا يمكن قراءة حالة الكيان في الذاكرة إلا للمنسق وحده، كما هو يتم التوضيح في القسم التالي.

مثال: إشارات التنسيق واستدعاءات الكيان

يمكن لوظائف التنسيق الوصول إلى الكيانات باستخدام واجهات برمجة التطبيقات على ربط مشغل التنسيق. يظهر الكود المثال التالي دالة منسق تتصل وترسل إشارات إلى كيان Counter .

قيد العملية:

[FunctionName("CounterOrchestration")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var entityId = new EntityId(nameof(Counter), "myCounter");

    // Two-way call to the entity which returns a value - awaits the response
    int currentValue = await context.CallEntityAsync<int>(entityId, "Get");
    if (currentValue < 10)
    {
        // One-way signal to the entity which updates the value - does not await a response
        context.SignalEntity(entityId, "Add", 1);
    }
}

عملية العامل المعزولة:

[Function("CounterOrchestration")]
public static async Task Run([OrchestrationTrigger] TaskOrchestrationContext context)
{
    var entityId = new EntityInstanceId(nameof(Counter), "myCounter");

    // Two-way call to the entity which returns a value - awaits the response
    int currentValue = await context.Entities.CallEntityAsync<int>(entityId, "Get");

    if (currentValue < 10)
    {
        // One-way signal to the entity which updates the value - does not await a response
        await context.Entities.SignalEntityAsync(entityId, "Add", 1);
    }
}

فقط التنسيقات يمكنها استدعاء الكيانات والحصول على استجابة، والتي قد تكون قيمة إرجاع أو استثناء. الدوال العميلة التي تستخدم ربط العميل يمكنها فقط الإشارة إلى الكيانات.

يمكن للمنسقين الوصول إلى الكيانات باستخدام واجهة برمجة تطبيقات الكيانات الخاصة بالسياق:

public class CounterOrchestration : TaskOrchestrator<string, int>
{
    public override async Task<int> RunAsync(TaskOrchestrationContext context, string entityKey)
    {
        var entityId = new EntityInstanceId(nameof(Counter), entityKey);

        // Two-way call to the entity which returns a value - awaits the response
        int currentValue = await context.Entities.CallEntityAsync<int>(entityId, nameof(Counter.Get));

        if (currentValue < 10)
        {
            // One-way signal to the entity - does not await a response
            await context.Entities.SignalEntityAsync(entityId, nameof(Counter.Add), 1);
        }

        return currentValue;
    }
}

فقط المنظمون يمكنهم استدعاء الكيانات والحصول على رد، والذي قد يكون قيمة إرجاع أو استثناء. العملاء يمكنهم فقط الإشارة إلى الكيانات.

ملحوظة

استدعاء كيان من منسق مشابه لاستدعاء نشاط. الفرق الرئيسي هو أن الكيانات هي كائنات دائمة لها عنوان (معرف الكيان) ودعم يحدد اسم العملية. الأنشطة لا توجد فيها دولة ولا تحمل مفهوم العمليات.

مثال: الكيان يرسل إشارات إلى كيان

يمكن لدالة الكيان إرسال إشارات إلى كيانات أخرى، أو حتى إلى نفسها، أثناء تنفيذها لعملية. على سبيل المثال، عدل مثال الكيان السابق Counter لإرسال إشارة "تم الوصول إلى الإنجاز" إلى كيان مراقبة عندما يصل العداد إلى 100.

قيد العملية:

   case "add":
        var currentValue = ctx.GetState<int>();
        var amount = ctx.GetInput<int>();
        if (currentValue < 100 && currentValue + amount >= 100)
        {
            ctx.SignalEntity(new EntityId("MonitorEntity", ""), "milestone-reached", ctx.EntityKey);
        }

        ctx.SetState(currentValue + amount);
        break;

عملية العامل المعزولة:

case "add":
    var currentValue = operation.State.GetState<int>();
    var amount = operation.GetInput<int>();
    if (currentValue < 100 && currentValue + amount >= 100)
    {
        operation.Context.SignalEntity(new EntityInstanceId("MonitorEntity", ""), "milestone-reached", operation.Context.EntityInstanceId);
    }

    operation.State.SetState(currentValue + amount);
    break;

تنسيق الكيان

أحيانا تحتاج إلى تنسيق العمليات بين عدة كيانات. على سبيل المثال، في تطبيق مصرفي، يمكن للكيانات تمثيل حسابات بنكية فردية. عندما تقوم بتحويل الأموال من حساب إلى آخر، يجب التأكد من أن الحساب المصدر يحتوي على ما يكفي من الأموال. تحتاج أيضا إلى تحديث كلا الحسابين كعملية واحدة متسقة.

مثال: تحويل الأموال

تستخدم التعليمات البرمجية الواردة في المثال التالي لتحويل الأموال بين كياني حساب باستخدام وظيفة المنسق. لتنسيق تحديثات الكيانات، استخدم قفلا لإنشاء قسم حرج في التنسيق.

ملحوظة

للتبسيط، يعيد هذا المثال استخدام Counter الكيان الذي تم تعريفه سابقا. في التطبيق الحقيقي، من الأفضل تعريف كيان أكثر تفصيلا BankAccount .

استخدم الطريقة LockAsync لإنشاء القسم الحرج.

// This is a method called by an orchestrator function
public static async Task<bool> TransferFundsAsync(
    string sourceId,
    string destinationId,
    int transferAmount,
    IDurableOrchestrationContext context)
{
    var sourceEntity = new EntityId(nameof(Counter), sourceId);
    var destinationEntity = new EntityId(nameof(Counter), destinationId);

    // Create a critical section to avoid race conditions.
    // No operations can be performed on either the source or
    // destination accounts until the locks are released.
    using (await context.LockAsync(sourceEntity, destinationEntity))
    {
        ICounter sourceProxy =
            context.CreateEntityProxy<ICounter>(sourceEntity);
        ICounter destinationProxy =
            context.CreateEntityProxy<ICounter>(destinationEntity);

        int sourceBalance = await sourceProxy.Get();

        if (sourceBalance >= transferAmount)
        {
            await sourceProxy.Add(-transferAmount);
            await destinationProxy.Add(transferAmount);

            // the transfer succeeded
            return true;
        }
        else
        {
            // the transfer failed due to insufficient funds
            return false;
        }
    }
}

في .NET، LockAsync تعود IDisposable. التخلص منها ينهي القسم الحرج. استخدمها مع كتلة using لتمثيل القسم الحرج.

في المثال السابق، تحول دالة المنسق الأموال من كيان مصدر إلى كيان وجهة. تقوم الطريقة LockAsync بقفل كل من كيانات الحساب المصدر والوجهة. يضمن هذا القفل أنه لا يمكن لأي عميل آخر الاستعلام أو تعديل حالة أي من الحسابين حتى يخرج منطق التنسيق من القسم الحرج في نهاية using البيان. هذا السلوك يمنع السحب على السحب على الحساب المصدر.

ملحوظة

عندما تنتهي التوزيع الأوركسترالي، سواء بشكل طبيعي أو مع خطأ، تنتهي أي مقاطع حرجة في السير ضمنيا، ويفك النظام جميع الأقفال.

سلوك المقطع الحيوي

تخلق هذه LockAsync الطريقة قسما نقديا في التوزيع الأوركسترالي. تمنع هذه المقاطع الهامة المنسقات الأخرى من إجراء تغييرات متداخلة على مجموعة محددة من الكيانات. داخليا، ترسل واجهة LockAsync برمجة التطبيقات عمليات "القفل" إلى الكيانات وتعود بعد استلامها استجابة "تم الحصول عليها من القفل" من كل كيان. كل من التامين بالقفل وفتح القفل تمثل عمليات مدمجة تدعمها جميع الكيانات.

لا يمكن للعملاء الآخرين تشغيل العمليات على كيان أثناء قفلاته. يضمن هذا السلوك أن مثيل منسق واحد فقط يمكنه تأمين الكيان في كل مرة. إذا حاول المتصل استدعاء عملية على كيان ما، في أثناء تأمينه بواسطة منسق، فإن هذه العملية توضع في قائمة انتظار وتعد عملية معلقة. لا تتم معالجة أية عمليات معلقة إلا بعد تحرير تأمين المنسق المحتفظ بالتأمين.

ملحوظة

يختلف هذا السلوك قليلا عن البدائيات المزامنة المستخدمة في معظم لغات البرمجة، مثل lock العبارة في C#. على سبيل المثال، في C#، يجب على جميع الخيوط استخدام العبارة lock لضمان التزامن الصحيح. ومع ذلك، لا تطلب الكيانات من جميع المتصلين تأمين الكيان صراحة. إذا قام أي متصل بتأمين كيان، يتم حظر كافة العمليات الأخرى على هذا الكيان ووضعها في قائمة الانتظار ليتم تنفيذها بعد تحرير هذا القفل.

الأقفال التي تطبق لتأمين الكيانات دائمة، لذلك فإنها تستمر حتى إذا تم إعادة تدوير عملية التنفيذ. يستمر النظام في الأقفال كجزء من حالة الكيان الدائمة.

على عكس المعاملات، لا تتراجع المقاطع الهامة تلقائيا عن التغييرات عند حدوث أخطاء. بدلا من ذلك، اكتب معالجة الأخطاء، مثل التراجع أو إعادة المحاولة، على سبيل المثال عن طريق اكتشاف الأخطاء أو الاستثناءات. التصميم المختار هذا مقصود. من الصعب التراجع تلقائيًا عن جميع آثار المنسق، ويعد هذا مستحيلًا بشكل عام، لأن المنسق يمكن أن يتولى تشغيل الأنشطة وإجراء استدعاء للخدمات الخارجية التي لا يمكن التراجع عنها. وقد تفشل أيضًا محاولات التراجع وتتطلب معالجة الأخطاء.

قواعد المقطع الحيوي

على عكس بدائيات القفل منخفضة المستوى في معظم لغات البرمجة، تضمن الأقسام الحرجة عدم وجود جمود. لمنع حدوث جمود، يفرض النظام القيود التالية:

  • لا يمكنك تعشيش الأقسام الحرجة.
  • لا يمكنك إنشاء توزيعات فرعية في الأقسام الحرجة.
  • يمكنك فقط استدعاء الكيانات التي تقفل في الأقسام الحرجة.
  • لا يمكنك استدعاء نفس الكيان باستخدام عدة استدعاءات متوازية في الأقسام الحرجة.
  • يمكنك فقط الإشارة إلى الكيانات خارج مجموعة القفل في الأقسام الحرجة.

إذا خالفت أيا من هذه القواعد، فإن وقت التشغيل يظهر خطأ، كما في LockingRulesViolationException .NET. رسالة الخطأ تشرح القاعدة التي تم خرقها.

مقارنة الكيانات الدائمة مع الفاعلين الافتراضيين

الكيانات المتانة تستخدم العديد من الأفكار من نموذج الممثل. إذا كنت على دراية بالممثلين، فقد تتعرف على عدة مفاهيم في هذا المقال. الكيانات المتينة تشبه الفاعلين الافتراضيين، وتسمى أيضا الحبوب، من مشروع أورليانز. على سبيل المثال:

  • أنت تتعامل مع الكيانات الدائمة باستخدام معرف الكيان.
  • تتم عمليات الكيانات الدائمة بشكل تسلسلي لمنع ظروف السباق.
  • الاتصال أو الإشارة إلى كيان يخلقه ضمنيا.
  • يقوم وقت التشغيل بإخراج الكيانات من الذاكرة عندما لا تكون تعمل على العمليات.

تشمل الاختلافات الرئيسية ما يلي:

  • الكيانات المتينة تعطي الأولوية للمتانة على الزمن، لذا قد لا تناسب التطبيقات التي تتطلب زمن استجابة صارمة.
  • الكيانات المتينة لا تتوقف الرسائل. أورليانز يرسل مهلة زمنية بعد فترة قابلة للتخصيص (30 ثانية افتراضيا).
  • تقوم الكيانات بتوصيل الرسائل بشكل موثوق ومنظم. يدعم Orleans التوصيل الموثوق والمنظم لرسائل البث، لكنه لا يضمن ذلك لجميع الرسائل بين الحبوب.
  • التنسيقات الموسيقية هي المكان الوحيد الذي يمكنك فيه استخدام طلب الاستجابة مع الكيانات. داخل الكيان، استخدم الرسائل أحادية الاتجاه (الإشارة)، كما في نموذج الممثل الأصلي.
  • الكيانات الدائمة لا تتعرض لتوقف تام. يمكن أن تتوقف أورليان، وتستمر الجمود حتى تنتهي الرسائل.
  • الكيانات المتينة تعمل مع التنسيقات المتانة وتدعم آليات القفل الموزعة.

الخطوات التالية