Entitas tahan lama

Fungsi entitas menentukan operasi yang membaca dan memperbarui potongan-potongan kecil status, yang disebut entitas tahan lama. Seperti fungsi orkestrator, fungsi entitas menggunakan jenis pemicu khusus yang disebut pemicu entitas. Tidak seperti fungsi orkestrator, fungsi entitas mengelola status entitas secara eksplisit alih-alih mewakili status melalui alur kontrol. Entitas membantu Anda menskalakan aplikasi dengan mendistribusikan pekerjaan di banyak entitas, masing-masing dengan status sederhana.

Entitas mendefinisikan operasi yang membaca dan memperbarui potongan-potongan kecil status, yang disebut entitas tahan lama. Tidak seperti orkestrator, entitas mengelola status secara eksplisit alih-alih mewakili status melalui alur kontrol. Entitas membantu Anda menskalakan aplikasi dengan mendistribusikan pekerjaan di banyak entitas, masing-masing dengan status sederhana.

Dukungan untuk entitas yang tahan lama

Fungsi entitas dan fitur terkait tersedia di Durable Functions 2.0 dan yang lebih baru.

Bahasa pemrograman Dukungan untuk entitas yang tahan lama
.NET terisolasi
.NET dalam proses
Java
Python
JavaScript
PowerShell
SDK Tugas Tahan Lama Dukungan untuk entitas yang tahan lama
.NET terisolasi
.NET dalam proses
Java
Python
JavaScript
PowerShell

Konsep umum untuk entitas yang tahan lama

Entitas bertindak seperti layanan kecil yang berkomunikasi dengan menggunakan pesan. Setiap entitas memiliki identitas unik dan, jika diperlukan, status internal. Entitas menjalankan operasi saat diminta. Operasi mungkin memperbarui status, memanggil layanan eksternal, atau menunggu respons. Entitas berkomunikasi dengan entitas lain, orkestrasi, dan klien melalui pesan yang dikirim oleh runtime melalui antrean dengan keandalan tinggi.

Untuk mencegah konflik, satu entitas menjalankan operasi secara serial, satu demi satu.

Nota

Saat Anda memanggil entitas, entitas memproses payload hingga selesai, lalu menjadwalkan eksekusi baru yang diaktifkan saat input baru tiba. Akibatnya, log eksekusi entitas Anda mungkin menunjukkan eksekusi tambahan setelah setiap pemanggilan. Itu yang diharapkan.

ID Entitas

Gunakan ID entitas untuk mengakses entitas. ID entitas adalah sepasang string yang secara unik mengidentifikasi instans entitas. Hal ini terdiri dari:

  • Nama entitas, yang mengidentifikasi jenis entitas. Contohnya, Counter. Nama ini cocok dengan nama fungsi entitas yang mengimplementasikan entitas. Ini tidak peka terhadap huruf besar/kecil.
  • Kunci entitas, yang secara unik mengidentifikasi entitas di antara semua entitas lain dengan nama yang sama. Misalnya, GUID.

Misalnya, Counter fungsi entitas dapat digunakan untuk menyimpan skor dalam game online. Setiap instans game memiliki ID entitas yang unik, seperti @Counter@Game1 dan @Counter@Game2. Untuk menargetkan entitas, tentukan ID entitasnya.

Operasi entitas

Untuk memanggil operasi pada entitas, tentukan:

  • ID entitas dari target.
  • Nama operasi, yang merupakan string yang menentukan operasi yang akan dilakukan. Misalnya, entitas Counter dapat mendukung operasi add, get, atau reset.
  • Input operasi, yang merupakan parameter opsional untuk operasi. Misalnya, add operasi mengambil jumlah bilangan bulat sebagai input.
  • Waktu terjadwal, yang merupakan parameter opsional untuk menentukan waktu pengiriman operasi. Misalnya, jadwalkan operasi untuk dijalankan beberapa hari kemudian.

Operasi dapat mengembalikan nilai hasil atau hasil kesalahan, seperti kesalahan JavaScript atau pengecualian .NET. Orkestrasi panggilan menerima hasil atau kesalahan.

Operasi dapat mengembalikan nilai hasil atau hasil kesalahan, seperti pengecualian .NET atau pengecualian Python. Pemanggil menerima hasil atau kesalahan.

Operasi entitas juga dapat membuat, membaca, memperbarui, dan menghapus status entitas. Runtime selalu mempertahankan status entitas dalam penyimpanan.

Tentukan entitas

Gunakan salah satu dari dua API untuk menentukan entitas dalam .NET:

Sintaks berbasis fungsi: Dalam sintaks berbasis fungsi, Anda menulis setiap entitas sebagai fungsi dan mengirimkan operasi di aplikasi Anda. Sintaks ini berfungsi dengan baik untuk entitas dengan status sederhana, beberapa operasi, atau serangkaian operasi dinamis, seperti dalam kerangka kerja aplikasi. Tetapi mungkin membosankan untuk dikelola karena tidak mendeteksi kesalahan tipe pada waktu kompilasi.

Sintaks berbasis kelas: Dalam sintaksis berbasis kelas, kelas dan metode .NET memodelkan entitas dan operasi. Sintaks ini membuat kode lebih mudah dibaca dan memungkinkan Anda memanggil operasi dengan cara yang aman. Ini adalah lapisan tipis di atas sintaks berbasis fungsi, sehingga Anda dapat mencampur kedua varian di aplikasi yang sama.

API yang Anda gunakan bergantung pada tempat fungsi C# Anda berjalan. Proses pekerja terisolasi disarankan, tetapi Anda juga dapat menjalankan dalam proses host.

Contoh berbasis fungsi dalam proses:

Contoh ini menunjukkan entitas sederhana Counter yang diimplementasikan sebagai fungsi tahan lama. Ini mendefinisikan tiga operasi—add, reset, dan get—yang menggunakan status bilangan bulat.

[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;
    }
}

Untuk informasi selengkapnya, lihat Sintaks berbasis fungsi.


Contoh berbasis kelas dalam proses:

Contoh ini menunjukkan entitas yang sama yang Counter diterapkan dengan menggunakan kelas dan metode.

[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>();
}

Entitas ini menyimpan keadaan dalam objek Counter yang berisi nilai penghitung saat ini. Durable Functions menserialisasikan dan mendeserialisasi objek ini dengan menggunakan pustaka Json.NET.

Untuk informasi selengkapnya, lihat Menentukan kelas entitas.


Contoh proses kerja berbasis fungsi terisolasi:

Contoh berikut menunjukkan entitas berdasarkan Counter fungsi dalam proses kerja yang terpisah. Ini mendukung add, , resetget, dan 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;
    });
}

Contoh proses pekerja terisolasi berbasis kelas:

Contoh berikut menunjukkan implementasi Counter entitas menggunakan kelas dan metode.

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);
    }
}

Durable Task SDK untuk .NET mendukung penentuan entitas menggunakan sintaks berbasis kelas. Anda dapat menerapkan TaskEntity<TState> kelas dasar untuk menentukan entitas Anda.

Contoh berikut menunjukkan entitas yang Counter diimplementasikan menggunakan Durable Task SDK:

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;
}

Untuk mendaftarkan entitas dengan pekerja:

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

Untuk memberi sinyal atau memanggil entitas dari orkestrator:

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;
    }
}

Mengakses entiti

Akses entitas dengan menggunakan komunikasi satu arah atau dua arah:

  • Memanggil entitas menggunakan komunikasi dua arah (bolak-balik). Kirim pesan operasi ke entitas, lalu tunggu pesan respons sebelum Anda melanjutkan. Pesan respons memberikan nilai hasil atau kesalahan (misalnya, kesalahan JavaScript atau pengecualian .NET).
  • Memberi sinyal entitas menggunakan komunikasi satu arah (aktifkan dan lupakan). Kirim pesan operasi tetapi jangan tunggu respons. Runtime menjamin pengiriman, tetapi pengirim tidak dapat mengamati nilai hasil atau kesalahan.

Mengakses entitas dari fungsi klien, fungsi orkestrator, atau fungsi entitas. Tidak setiap konteks mendukung kedua jenis komunikasi:

  • Fungsi klien mendukung entitas penandaan dan membaca keadaan entitas.
  • Fungsi orkestrator mendukung entitas sinyal dan panggilan.
  • Fungsi entitas mendukung entitas pensinyalan.

Akses entitas dengan menggunakan komunikasi satu arah atau dua arah:

  • Memanggil entitas menggunakan komunikasi dua arah (bolak-balik). Kirim pesan operasi ke entitas, lalu tunggu pesan respons sebelum Anda melanjutkan. Pesan respons memberikan nilai hasil atau kesalahan.
  • Memberi sinyal entitas menggunakan komunikasi satu arah (aktifkan dan lupakan). Kirim pesan operasi tetapi jangan tunggu respons. Runtime menjamin pengiriman, tetapi pengirim tidak dapat mengamati nilai hasil atau kesalahan.

Mengakses entitas dari klien atau orkestrator. Tidak setiap konteks mendukung kedua jenis komunikasi:

  • Klien mendukung entitas pensinyalan dan membaca status entitas.
  • Orkestrator mendukung entitas sinyal dan panggilan.

Contoh berikut menunjukkan cara mengakses entitas.

Contoh: klien memberi sinyal entitas

Untuk mengakses entitas dari Fungsi Azure biasa, yang juga dikenal sebagai fungsi klien, gunakan pengikatan klien entity. Contoh berikut menunjukkan fungsi yang dipicu oleh antrean untuk memberi sinyal kepada entitas dengan menggunakan pengikatan ini.

Nota

Sederhananya, contoh berikut menunjukkan sintaks yang diketik secara mudah untuk mengakses entitas. Secara umum, mengakses entitas melalui antarmuka karena memberikan lebih banyak pengecekan tipe.

Dalam proses:

Dalam proses:

[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);
}

Proses pekerja terisolasi:

[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);
}

Istilah sinyal berarti bahwa pemanggilan API entitas adalah satu arah dan asinkron. Fungsi klien tidak dapat mengetahui kapan entitas memproses operasi. Fungsi klien tidak dapat mengamati nilai hasil atau pengecualian.

Untuk mengakses entitas dari klien, gunakan DurableTaskClient untuk memberi sinyal atau membaca status entitas.

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

Istilah sinyal berarti bahwa pemanggilan API entitas adalah satu arah dan asinkron. Klien tidak dapat mengetahui kapan entitas memproses operasi.

Contoh: klien membaca status entitas

Mengkueri status entitas dari fungsi klien:

Dalam proses:

[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);
}

Proses pekerja terisolasi:

[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;
}

Klien dapat mengkueri status entitas:

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}");
}

Kueri status entitas dikirim ke penyimpanan pelacakan yang tahan lama dan mengembalikan status entitas yang terakhir dipertahankan. Status ini selalu menjadi status "committed", yaitu, tidak pernah menjadi status perantara sementara yang diasumsikan di tengah-tengah pelaksanaan operasi. Tetapi status ini dapat basi dibandingkan dengan status dalam memori entitas. Hanya orkestrasi yang dapat membaca status dalam memori entitas, seperti yang dijelaskan di bagian berikut.

Contoh: sinyal orkestrasi dan memanggil entitas

Fungsi orkestrator dapat mengakses entitas dengan menggunakan API pada pengikatan pemicu orkestrasi. Contoh kode berikut menunjukkan fungsi orkestrator memanggil dan memberi sinyal entitas Counter .

Dalam proses:

[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);
    }
}

Proses pekerja terisolasi:

[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);
    }
}

Hanya orkestrasi yang dapat memanggil entitas dan mendapatkan respons, yang dapat menjadi nilai pengembalian atau pengecualian. Fungsi klien yang menggunakan pengikatan klien hanya dapat memberi sinyal entitas.

Orkestrator dapat mengakses entitas menggunakan API Entitas konteks:

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;
    }
}

Hanya orkestrator yang dapat memanggil entitas dan mendapatkan respons, yang dapat menjadi nilai pengembalian atau pengecualian. Klien hanya dapat memberi sinyal entitas.

Nota

Memanggil entitas dari orkestrator mirip dengan memanggil aktivitas. Perbedaan utamanya adalah bahwa entitas adalah objek tahan lama dengan alamat (ID entitas) dan dukungan yang menentukan nama operasi. Aktivitas tanpa status dan tidak memiliki konsep operasi.

Contoh: entitas mengirimkan sinyal ke entitas

Fungsi entitas dapat mengirim sinyal ke entitas lain, atau bahkan diri sendiri, saat menjalankan operasi. Misalnya, ubah contoh entitas sebelumnya Counter untuk mengirim sinyal "milestone-reached" ke entitas monitor saat penghitung mencapai 100.

Dalam proses:

   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;

Proses pekerja terisolasi:

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;

Koordinasi entitas

Terkadang Anda perlu mengoordinasikan operasi di beberapa entitas. Misalnya, dalam aplikasi perbankan, entitas dapat mewakili rekening bank individual. Ketika Anda mentransfer dana dari satu akun ke akun lain, Anda perlu memastikan akun sumber memiliki cukup dana. Anda juga perlu memperbarui kedua akun sebagai satu operasi yang konsisten.

Contoh: Mentransfer dana (C#)

Contoh kode berikut mentransfer dana antara dua entitas akun dengan menggunakan fungsi orkestrator. Untuk mengoordinasikan pembaruan entitas, gunakan LockAsync metode untuk membuat bagian penting dalam orkestrasi.

Nota

Untuk kesederhanaan, contoh ini menggunakan kembali entitas yang Counter ditentukan sebelumnya. Dalam aplikasi nyata, lebih baik menentukan entitas yang lebih rinci BankAccount .

// 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;
        }
    }
}

Di .NET, LockAsync mengembalikan IDisposable. Membuangnya mengakhiri bagian penting. Gunakan dengan blok using untuk mewakili bagian kritis.

Dalam contoh sebelumnya, fungsi orkestrator mentransfer dana dari entitas sumber ke entitas tujuan. Metode ini LockAsync mengunci entitas akun sumber dan tujuan. Penguncian ini memastikan bahwa tidak ada klien lain yang dapat mengkueri atau mengubah status salah satu akun hingga logika orkestrasi keluar dari bagian penting di akhir using pernyataan. Perilaku ini mencegah penarikan melebihi saldo pada akun sumber.

Nota

Ketika orkestrasi berakhir, baik secara normal atau dengan kesalahan, setiap bagian penting yang sedang berlangsung berakhir secara implisit, dan sistem melepaskan semua kunci.

Perilaku bagian kritis

Metode LockAsync ini membuat bagian kritis dalam orkestrasi. Bagian kritis ini mencegah orkestrasi lain melakukan perubahan tumpang tindih ke sekumpulan entitas tertentu. Secara internal, LockAsync API mengirim operasi "kunci" ke entitas dan kembali setelah menerima respons "kunci yang diperoleh" dari setiap entitas. Mengunci dan membuka kunci adalah operasi bawaan yang didukung oleh semua entitas.

Klien lain tidak dapat menjalankan operasi pada entitas saat dikunci. Perilaku ini memastikan bahwa hanya satu instans orkestrasi yang dapat mengunci entitas pada satu waktu. Jika penelepon mencoba memanggil operasi pada entitas saat terkunci oleh orkestrasi, operasi tersebut ditempatkan dalam antrean operasi yang tertunda. Tidak ada operasi yang tertunda diproses sampai setelah orkestrasi penahanan melepaskan kuncinya.

Nota

Perilaku ini sedikit berbeda dari primitif sinkronisasi yang digunakan dalam sebagian besar bahasa pemrograman, seperti lock pernyataan dalam C#. Misalnya, dalam C#, semua utas perlu menggunakan pernyataan lock untuk memastikan sinkronisasi yang tepat. Entitas, bagaimanapun, tidak mengharuskan semua penelepon untuk secara eksplisit mengunci entitas. Jika ada pemanggil yang mengunci entitas, semua operasi lain pada entitas tersebut diblokir dan antri di belakang kunci tersebut.

Kunci pada entitas bersifat tahan lama, sehingga mereka bertahan bahkan jika proses eksekusi didaur ulang. Sistem menyimpan kunci sebagai bagian dari keadaan persisten entitas.

Tidak seperti transaksi, bagian penting tidak secara otomatis mengembalikan perubahan saat kesalahan terjadi. Sebagai gantinya, tulis penanganan kesalahan, seperti putar kembali atau coba lagi, misalnya dengan menangkap kesalahan atau pengecualian. Pilihan desain ini disengaja. Mengembalikan secara otomatis semua efek orkestrasi sulit atau bahkan tidak mungkin dilakukan, karena orkestrasi dapat menjalankan aktivitas dan melakukan panggilan ke layanan eksternal yang tidak dapat dikembalikan. Selain itu, upaya untuk mundur mungkin gagal dan memerlukan penanganan kesalahan lebih lanjut.

Regulasi Bagian Kritis

Tidak seperti primitif penguncian tingkat rendah dalam sebagian besar bahasa pemrograman, bagian penting dijamin tidak mengalami kebuntuan. Untuk mencegah kebuntuan, kami memberlakukan pembatasan berikut:

  • Bagian kritis tidak dapat bersarang.
  • Bagian kritis tidak dapat membuat suborkestrasi.
  • Bagian kritis hanya dapat memanggil entitas yang dikunci oleh mereka.
  • Bagian kritis tidak dapat memanggil entitas yang sama menggunakan beberapa panggilan paralel.
  • Bagian penting hanya dapat memberi sinyal entitas di luar set kunci.

Setiap pelanggaran aturan ini menyebabkan kesalahan runtime, seperti LockingRulesViolationException di .NET, yang mencakup pesan yang menjelaskan aturan apa yang rusak.

Perbandingan entitas tahan lama dengan aktor virtual

Entitas berkelanjutan menggunakan berbagai ide dari model aktor. Jika Anda terbiasa dengan aktor, Anda mungkin mengenali beberapa konsep dalam artikel ini. Entitas tahan lama mirip dengan aktor virtual, juga disebut biji-bijian, dari proyek Orleans. Contohnya:

  • Anda mengakses entitas yang tahan lama dengan menggunakan ID entitas.
  • Operasi entitas tahan lama berjalan secara serial untuk mencegah kondisi perlombaan.
  • Memanggil atau memberi sinyal kepada suatu entitas akan menciptakan entitas tersebut secara implisit.
  • Runtime membongkar entitas-entitas dari memori ketika mereka tidak menjalankan operasi.

Perbedaan utama meliputi:

  • Entitas tahan lama memprioritaskan durabilitas dibandingkan latensi, sehingga mungkin tidak sesuai dengan aplikasi dengan persyaratan latensi yang ketat.
  • Entitas tahan lama tidak kehabisan waktu pesan. Orleans kehabisan waktu pesan setelah periode yang dapat dikonfigurasi (30 detik secara default).
  • Entitas mengirimkan pesan dengan andal dan berurutan. Orleans mendukung pengiriman yang dapat diandalkan dan terurut untuk pesan streaming, tetapi tidak menjaminnya untuk semua pesan antar grain.
  • Orkestrasi adalah satu-satunya tempat di mana Anda dapat menggunakan strategi request-response dengan entitas. Di dalam entitas, gunakan pengiriman pesan satu arah (sinyal), seperti pada model aktor yang asli.
  • Entitas tahan lama tidak mengalami kebuntuan. Orleans dapat mengalami deadlock, dan deadlock berlanjut sampai pesan mengalami batas waktu habis.
  • Entitas tahan lama bekerja dengan orkestrasi tahan lama dan mendukung mekanisme penguncian terdistribusi.

Langkah berikutnya