Share via


Varlık işlevleri

Varlık işlevleri, dayanıklı varlıklar olarak bilinen küçük durum parçalarını okumak ve güncelleştirmek için işlemleri tanımlar. Orchestrator işlevleri gibi varlık işlevleri de varlık tetikleyicisi olan özel tetikleyici türüne sahip işlevlerdir. Orchestrator işlevlerinden farklı olarak varlık işlevleri, denetim akışı aracılığıyla durumu örtük olarak temsil etmek yerine varlığın durumunu açıkça yönetir. Varlıklar, işi her birinde mütevazı boyutta bir duruma sahip birçok varlık arasında dağıtarak uygulamaların ölçeğini genişletmeye yönelik bir araç sağlar.

Dekont

Varlık işlevleri ve ilgili işlevler yalnızca Dayanıklı İşlevler 2.0 ve üzerinde kullanılabilir. Şu anda .NET in-proc, .NET yalıtılmış çalışanı, JavaScript ve Python'da desteklenir, ancak PowerShell veya Java'da desteklenmez.

Önemli

Varlık işlevleri şu anda PowerShell ve Java'da desteklenmiyor.

Genel kavramlar

Varlıklar, iletiler aracılığıyla iletişim kuran küçük hizmetler gibi davranır. Her varlığın benzersiz bir kimliği ve iç durumu vardır (varsa). Hizmetler veya nesneler gibi varlıklar da istendiğinde işlemleri gerçekleştirir. Bir işlem yürütürken varlığın iç durumunu güncelleştirebilir. Ayrıca dış hizmetleri çağırabilir ve yanıt bekleyebilir. Varlıklar, güvenilir kuyruklar aracılığıyla örtük olarak gönderilen iletileri kullanarak diğer varlıklarla, düzenlemelerle ve istemcilerle iletişim kurar.

Çakışmaları önlemek için, tek bir varlık üzerindeki tüm işlemlerin seri olarak, yani birbiri ardına yürütülmesi garanti edilir.

Dekont

Bir varlık çağrıldığında, yükü tamamlanmaya kadar işler ve daha sonra gelecek girişler geldiğinde etkinleştirmek için yeni bir yürütme zamanlar. Sonuç olarak, varlık yürütme günlükleriniz her varlık çağrısının ardından ek bir yürütme gösterebilir; bu beklenen bir durumdur.

Varlık Kimliği

Varlıklara benzersiz bir tanımlayıcı olan varlık kimliği aracılığıyla erişilir. Varlık kimliği, bir varlık örneğini benzersiz olarak tanımlayan bir dize çiftidir. Şunlardan oluşur:

  • Varlık adı, varlığın türünü tanımlayan bir addır. Örnek olarak "Sayaç" yer alır. Bu ad, varlığı uygulayan varlık işlevinin adıyla eşleşmelidir. Büyük/küçük harfe duyarlı değildir.
  • Varlık anahtarı, aynı ada sahip diğer tüm varlıklar arasında varlığı benzersiz olarak tanımlayan bir dizedir. Guid örneği verilmiştir.

Örneğin, çevrimiçi Counter bir oyunda puanı korumak için bir varlık işlevi kullanılabilir. Oyunun her örneğinin ve @Counter@Game2gibi @Counter@Game1 benzersiz bir varlık kimliği vardır. Belirli bir varlığı hedefleyen tüm işlemler için parametre olarak bir varlık kimliği belirtilmesi gerekir.

Varlık işlemleri

Bir varlıkta bir işlemi çağırmak için şunları belirtin:

  • Hedef varlığın Varlık Kimliği .
  • gerçekleştirilecek işlemi belirten bir dize olan işlem adı. Örneğin, Counter varlık , getveya reset işlemlerini destekleyebileceğindenadd.
  • İşlem girişi, işlem için isteğe bağlı bir giriş parametresidir. Örneğin, ekleme işlemi giriş olarak bir tamsayı miktarı alabilir.
  • zamanlanmış saat, işlemin teslim süresini belirtmek için isteğe bağlı bir parametredir. Örneğin, bir işlem gelecekte birkaç gün çalışacak şekilde güvenilir bir şekilde zamanlanabilir.

İşlemler javascript hatası veya .NET özel durumu gibi bir sonuç değeri veya hata sonucu döndürebilir. Bu sonuç veya hata, işlemi çağıran düzenlemelerde oluşur.

Varlık işlemi ayrıca varlığın durumunu oluşturabilir, okuyabilir, güncelleştirebilir ve silebilir. Varlığın durumu her zaman kalıcı olarak depolamada kalır.

Varlıkları tanımlama

Varlıkları işlev tabanlı bir söz dizimi kullanarak tanımlarsınız; burada varlıklar işlev olarak temsil edilir ve işlemler uygulama tarafından açıkça gönderilir.

Şu anda .NET'te varlıkları tanımlamak için iki ayrı API vardır:

İşlev tabanlı söz dizimi kullandığınızda, varlıklar işlev olarak gösterilir ve işlemler uygulama tarafından açıkça gönderilir. Bu söz dizimi, basit durumu, birkaç işlemi veya uygulama çerçevelerinde olduğu gibi dinamik bir işlem kümesi olan varlıklar için iyi çalışır. Derleme zamanında tür hatalarını yakalamadığından bu söz diziminde bakım yapmak yorucu olabilir.

Belirli API'ler, C# işlevlerinizin yalıtılmış bir çalışan işleminde mi (önerilen) yoksa konakla aynı işlemde mi çalıştığına bağlıdır.

Aşağıdaki kod, dayanıklı işlev olarak uygulanan basit Counter bir varlık örneğidir. Bu işlev, addresether biri tamsayı durumunda çalışan , ve getolmak üzere üç işlemi tanımlar.

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

İşlev tabanlı söz dizimi ve nasıl kullanılacağı hakkında daha fazla bilgi için bkz . İşlev tabanlı söz dizimi.

Dayanıklı varlıklar, npm paketinin 1.3.0 sürümünden durable-functions itibaren JavaScript'te kullanılabilir. Aşağıdaki kod, Counter JavaScript'te yazılmış dayanıklı bir işlev olarak uygulanan varlıktır.

Counter/function.json

{
  "bindings": [
    {
      "name": "context",
      "type": "entityTrigger",
      "direction": "in"
    }
  ],
  "disabled": false
}

Counter/index.js

const df = require("durable-functions");

module.exports = df.entity(function(context) {
    const currentValue = context.df.getState(() => 0);
    switch (context.df.operationName) {
        case "add":
            const amount = context.df.getInput();
            context.df.setState(currentValue + amount);
            break;
        case "reset":
            context.df.setState(0);
            break;
        case "get":
            context.df.return(currentValue);
            break;
    }
});

Aşağıdaki kod, Python'da Counter yazılmış dayanıklı bir işlev olarak uygulanan varlıktır.

import azure.functions as func
import azure.durable_functions as df

# Entity function called counter
@myApp.entity_trigger(context_name="context")
def Counter(context):
    current_value = context.get_state(lambda: 0)
    operation = context.operation_name
    if operation == "add":
        amount = context.get_input()
        current_value += amount
    elif operation == "reset":
        current_value = 0
    elif operation == "get":
        context.set_result(current_value)
    context.set_state(current_value)

Varlıklara erişme

Varlıklara tek yönlü veya çift yönlü iletişim kullanılarak erişilebilir. Aşağıdaki terminoloji, iki iletişim türünü ayırt eder:

  • Bir varlığı çağırmak iki yönlü (gidiş dönüş) iletişim kullanır. Varlığa bir işlem iletisi gönderir ve devam etmeden önce yanıt iletisini beklersiniz. Yanıt iletisi javascript hatası veya .NET özel durumu gibi bir sonuç değeri veya hata sonucu sağlayabilir. Bu sonuç veya hata daha sonra çağıran tarafından gözlemlenir.
  • Bir varlığın sinyalini tek yönlü (yangın ve unutma) iletişim kullanır. bir işlem iletisi gönderirsiniz, ancak yanıt beklemezsiniz. İletinin nihai olarak teslim edilmesi garanti edilir ancak gönderen, ne zaman ve ne zaman sonuç değeri veya hata gözlemleyece bilmemektedir.

Varlıklara istemci işlevleri içinden, orchestrator işlevleri içinden veya varlık işlevleri içinden erişilebilir. İletişimin her biçimi tüm bağlamlar tarafından desteklenmez:

  • İstemcilerin içinden varlıklara sinyal verebilir ve varlık durumunu okuyabilirsiniz.
  • Düzenlemelerden varlıklara sinyal verebilir ve varlıkları çağırabilirsiniz.
  • Varlıkların içinden varlıklara sinyal gönderebilirsiniz.

Aşağıdaki örneklerde varlıklara erişmenin bu çeşitli yolları gösterilmektedir.

Örnek: İstemci bir varlığa sinyal gönderir

İstemci işlevi olarak da bilinen sıradan bir Azure İşlevi'nden varlıklara erişmek için varlık istemci bağlamasını kullanın. Aşağıdaki örnekte, bu bağlamayı kullanarak bir varlığa işaret eden kuyrukla tetiklenen bir işlev gösterilmektedir.

Dekont

Kolaylık olması için, aşağıdaki örneklerde varlıklara erişmek için gevşek yazılan söz dizimi gösterilmektedir. Genel olarak, daha fazla tür denetimi sağladığından varlıklara arabirimler aracılığıyla erişmenizi öneririz.

[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);
}
const df = require("durable-functions");

module.exports = async function (context) {
    const client = df.getClient(context);
    const entityId = new df.EntityId("Counter", "myCounter");
    await client.signalEntity(entityId, "add", 1);
};
import azure.functions as func
import azure.durable_functions as df

# An HTTP-Triggered Function with a Durable Functions Client to set a value on a durable entity
@myApp.route(route="entitysetvalue")
@myApp.durable_client_input(client_name="client")
async def http_set(req: func.HttpRequest, client):
    logging.info('Python HTTP trigger function processing a request.')
    entityId = df.EntityId("Counter", "myCounter")
    await client.signal_entity(entityId, "add", 1)
    return func.HttpResponse("Done", status_code=200)

Sinyal terimi, varlık API çağrısının tek yönlü ve zaman uyumsuz olduğu anlamına gelir. Bir istemci işlevinin varlığın işlemi ne zaman işlediğini bilmesi mümkün değildir. Ayrıca, istemci işlevi herhangi bir sonuç değerini veya özel durumu gözlemleyemez.

Örnek: İstemci varlık durumunu okur

İstemci işlevleri, aşağıdaki örnekte gösterildiği gibi bir varlığın durumunu da sorgulayabilir:

[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);
}
const df = require("durable-functions");

module.exports = async function (context) {
    const client = df.getClient(context);
    const entityId = new df.EntityId("Counter", "myCounter");
    const stateResponse = await client.readEntityState(entityId);
    return stateResponse.entityState;
};
# An HTTP-Triggered Function with a Durable Functions Client to retrieve the state of a durable entity
@myApp.route(route="entityreadvalue")
@myApp.durable_client_input(client_name="client")
async def http_read(req: func.HttpRequest, client):
    entityId = df.EntityId("Counter", "myCounter")
    entity_state_result = await client.read_entity_state(entityId)
    entity_state = "No state found"
    if entity_state_result.entity_exists:
      entity_state = str(entity_state_result.entity_state)
    return func.HttpResponse(entity_state)

Varlık durumu sorguları Dayanıklı izleme deposuna gönderilir ve varlığın en son kalıcı durumunu döndürür. Bu durum her zaman "işlenen" bir durumdur, yani bir işlemi yürütmenin ortasında hiçbir zaman geçici bir ara durum varsayılır. Ancak, varlığın bellek içi durumuna kıyasla bu durumun eski olması mümkündür. Aşağıdaki bölümde açıklandığı gibi yalnızca düzenleme işlemleri bir varlığın bellek içi durumunu okuyabilir.

Örnek: Orchestration bir varlığı sinyaller ve çağırır

Orchestrator işlevleri, düzenleme tetikleyicisi bağlaması üzerindeki API'leri kullanarak varlıklara erişebilir. Aşağıdaki örnek kod, bir varlığı çağıran ve işaretleyen bir Counter orchestrator işlevini gösterir.

[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);
    }
}
const df = require("durable-functions");

module.exports = df.orchestrator(function*(context){
    const entityId = new df.EntityId("Counter", "myCounter");

    // Two-way call to the entity which returns a value - awaits the response
    currentValue = yield context.df.callEntity(entityId, "get");
});

Dekont

JavaScript şu anda bir düzenleyiciden varlık sinyallerini desteklememektedir. Bunun yerine callEntity kullanın.

@myApp.orchestration_trigger(context_name="context")
def orchestrator(context: df.DurableOrchestrationContext):
    entityId = df.EntityId("Counter", "myCounter")
    context.signal_entity(entityId, "add", 3)
    logging.info("signaled entity")
    state = yield context.call_entity(entityId, "get")
    return state

Yalnızca düzenlemeler varlıkları çağırabilir ve bir yanıt alabilir; bu bir dönüş değeri veya özel durum olabilir. İstemci bağlamasını kullanan istemci işlevleri yalnızca varlıklara sinyal verebilir.

Dekont

Orchestrator işlevinden bir varlığı çağırmak, orchestrator işlevinden etkinlik işlevini çağırmaya benzer. Temel fark, varlık işlevlerinin varlık kimliği olan bir adrese sahip dayanıklı nesneler olmasıdır. Varlık işlevleri bir işlem adı belirtmeyi destekler. Öte yandan etkinlik işlevleri durum bilgisi yoktur ve işlem kavramına sahip değildir.

Örnek: Varlık bir varlığa işaret eder

Varlık işlevi, bir işlemi yürütürken diğer varlıklara veya hatta kendisine sinyal gönderebilir. Örneğin, sayaç 100 değerine ulaştığında bazı izleyici varlığına "kilometre taşına ulaşıldı" sinyali gönderebilmesi için önceki Counter varlık örneğini değiştirebiliriz.

   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":
        const amount = context.df.getInput();
        if (currentValue < 100 && currentValue + amount >= 100) {
            const entityId = new df.EntityId("MonitorEntity", "");
            context.df.signalEntity(entityId, "milestone-reached", context.df.instanceId);
        }
        context.df.setState(currentValue + amount);
        break;

Dekont

Python henüz varlık-varlık sinyallerini desteklememektedir. Lütfen bunun yerine varlıklara sinyal gönderirken bir düzenleyici kullanın.

Varlık koordinasyonu

İşlemleri birden çok varlık arasında koordine etmeniz gereken zamanlar olabilir. Örneğin, bir bankacılık uygulamasında, tek tek banka hesaplarını temsil eden varlıklarınız olabilir. Bir hesaptan diğerine fon aktardığınızda, kaynak hesabın yeterli fona sahip olduğundan emin olmanız gerekir. Ayrıca hem kaynak hem de hedef hesaplardaki güncelleştirmelerin işlemsel olarak tutarlı bir şekilde yapıldığından emin olmanız gerekir.

Örnek: Fon aktarma

Aşağıdaki örnek kod, bir orchestrator işlevi kullanarak iki hesap varlığı arasında fon aktarır. Varlık güncelleştirmelerini koordine etmek, düzenlemede LockAsync kritik bir bölüm oluşturmak için yönteminin kullanılmasını gerektirir.

Dekont

Kolaylık olması için, bu örnekte daha önce tanımlanan varlık yeniden kullanılır Counter . Gerçek bir uygulamada daha ayrıntılı BankAccount bir varlık tanımlamak daha iyi olacaktır.

// 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'te, LockAsync atıldığında kritik bölümü sona erdiren değerini döndürür IDisposable. Bu IDisposable sonuç, kritik bölümün bozulmamış bir gösterimini almak için bir using blokla birlikte kullanılabilir.

Yukarıdaki örnekte, bir düzenleyici işlevi kaynak varlıktan hedef varlığa fon aktarır. yöntemi hem LockAsync kaynak hem de hedef hesap varlıklarını kilitledi. Bu kilitleme, düzenleme mantığı deyiminin sonundaki using kritik bölümden çıkana kadar başka hiçbir istemcinin her iki hesabın durumunu sorgulayamadığından veya değiştiremediğinden emin oldu. Bu davranış, kaynak hesaptan fazla çizim yapma olasılığını engeller.

Dekont

Düzenleme normal olarak veya hatayla sonlandırıldığında, devam eden tüm kritik bölümler örtük olarak sonlandırılır ve tüm kilitler serbest bırakılır.

Kritik bölüm davranışı

yöntemi, LockAsync bir düzenlemede kritik bir bölüm oluşturur. Bu kritik bölümler, diğer düzenlemelerin belirli bir varlık kümesinde çakışan değişiklikler yapmasını engeller. API şirket LockAsync içinde varlıklara "kilit" işlemleri gönderir ve aynı varlıkların her birinden "kilit alındı" yanıt iletisi aldığında döndürür. Hem kilit hem de kilit açma, tüm varlıklar tarafından desteklenen yerleşik işlemlerdir.

Bir varlık kilitli durumdayken diğer istemcilerden hiçbir işleme izin verilmez. Bu davranış, bir varlığı aynı anda yalnızca bir düzenleme örneğinin kilitleyebilmesini sağlar. Çağıran bir düzenleme tarafından kilitlenmiş bir varlık üzerinde bir işlemi çağırmaya çalışırsa, bu işlem bekleyen bir işlem kuyruğuna yerleştirilir. Bekletme düzenlemesi kilidini serbest bırakana kadar bekleyen hiçbir işlem işlenmez.

Dekont

Bu davranış, C# deyimi gibi lock çoğu programlama dilinde kullanılan eşitleme temel öğelerinden biraz farklıdır. Örneğin, C# dilinde deyimi, lock birden çok iş parçacığı arasında düzgün eşitleme sağlamak için tüm iş parçacıkları tarafından kullanılmalıdır. Ancak varlıklar, tüm çağıranların bir varlığı açıkça kilitlemesini gerektirmez. Herhangi bir çağıran bir varlığı kilitlerse, bu varlık üzerindeki diğer tüm işlemler engellenir ve bu kilidin arkasında kuyruğa alınır.

Varlıklardaki kilitler dayanıklıdır, bu nedenle yürütme işlemi geri dönüştürülse bile kalıcı olur. Kilitler, bir varlığın dayanıklı durumunun bir parçası olarak dahili olarak kalıcıdır.

İşlemlerden farklı olarak, kritik bölümler hatalar oluştuğunda değişiklikleri otomatik olarak geri almaz. Bunun yerine, geri alma veya yeniden deneme gibi tüm hata işleme işlemleri, örneğin hataları veya özel durumları yakalayarak açıkça kodlanmalıdır. Bu tasarım seçimi kasıtlıdır. Düzenleme işlemleri etkinlikleri çalıştırabileceğinden ve geri alınamaz dış hizmetlere çağrılar gerçekleştirebileceğinden, bir düzenlemenin tüm etkilerini otomatik olarak geri almak zor veya genel olarak imkansızdır. Ayrıca, geri alma girişimleri başarısız olabilir ve daha fazla hata işleme gerektirebilir.

Kritik bölüm kuralları

Çoğu programlama dilindeki düşük düzeyli kilitleme temel öğelerinin aksine kritik bölümlerin kilitlenmemesi garanti edilir. Kilitlenmeleri önlemek için aşağıdaki kısıtlamaları uygularız:

  • Kritik bölümler iç içe yerleştirilemiyor.
  • Kritik bölümler alt etki oluşturamaz.
  • Kritik bölümler yalnızca kilitledikleri varlıkları çağırabilir.
  • Kritik bölümler birden çok paralel çağrı kullanarak aynı varlığı çağıramaz.
  • Kritik bölümler yalnızca kilitlenmedikleri varlıklara sinyal verebilir.

Bu kuralların ihlal edilmesi, hangi kuralın bozulduğunu açıklayan bir ileti içeren .NET gibi LockingRulesViolationException bir çalışma zamanı hatasına neden olur.

Sanal aktörlerle karşılaştırma

Dayanıklı varlık özelliklerinin çoğu aktör modelden ilham alır. Aktörleri zaten biliyorsanız, bu makalede açıklanan kavramların çoğunu tanıyabilirsiniz. Dayanıklı varlıklar, Orleans projesi tarafından popülerleştirilen sanal aktörlere veya tahıllara benzer. Örneğin:

  • Dayanıklı varlıklar bir varlık kimliği aracılığıyla adreslenebilir.
  • Dayanıklı varlık işlemleri, yarış koşullarını önlemek için tek tek seri olarak yürütülür.
  • Dayanıklı varlıklar çağrıldıklarında veya sinyal gönderildiğinde örtük olarak oluşturulur.
  • Dayanıklı varlıklar, işlemler yürütülmediğinde bellekten sessizce kaldırılır.

Dikkat edilmesi gereken bazı önemli farklılıklar vardır:

  • Dayanıklı varlıklar gecikme süresine göre dayanıklılığı önceliklendirir ve bu nedenle katı gecikme süresi gereksinimleri olan uygulamalar için uygun olmayabilir.
  • Dayanıklı varlıklarda iletiler için yerleşik zaman aşımları yoktur. Orleans'ta, tüm mesajlar yapılandırılabilir bir süreden sonra zaman aşımına uğradı. Varsayılan değer 30 saniyedir.
  • Varlıklar arasında gönderilen iletiler güvenilir ve sırayla teslim edilir. Orleans'ta, akışlar aracılığıyla gönderilen içerik için güvenilir veya siparişli teslimat desteklenir, ancak tahıllar arasındaki tüm iletiler için garanti edilmez.
  • Varlıklardaki istek yanıtı desenleri düzenlemelerle sınırlıdır. Varlıklar içinden, orijinal aktör modelinde olduğu gibi ve Orleans'taki tahıllardan farklı olarak yalnızca tek yönlü mesajlaşmaya (sinyal gönderme olarak da bilinir) izin verilir.
  • Dayanıklı varlıklar kilitlenmez. Orleans'ta kilitlenmeler yaşanabilir ve iletiler zaman aşımına uyana kadar çözülmez.
  • Dayanıklı varlıklar dayanıklı düzenlemelerle kullanılabilir ve dağıtılmış kilitleme mekanizmalarını destekler.

Sonraki adımlar