Kalıcı orkestrasyonlarda dış olayları işleme

Dış olaylar, insan onayları, web kancası geri çağırmaları veya diğer sistemler gibi dış kaynaklardan gelen sinyalleri alabilmesi için orkestrasyonların çalışmasına müsaade eder. Bu makalede, dayanıklı düzenlemelerinizde dış olayları bekleme, gönderme ve işleme işlemleri gösterilir.

Tip

Olayları bir orkestrasyona göndermek mi istiyorsunuz? Olayları gönder'e atlayın.

Orchestrator işlevleri, dış olayları bekleyebilir ve dinleyebilir. Dayanıklı İşlevler'in bu özelliği genellikle insan etkileşimini veya diğer dış tetikleyicileri işlemek için kullanışlıdır.

Uyarı

Dış olaylar tek yönlü asenkron işlemlerdir. Bunlar, olayı gönderen istemcinin orchestrator işlevinden zaman uyumlu bir yanıta ihtiyaç duyduğu durumlar için uygun değildir.

Orkestrasyonlar, dış olayları bekleyebilir ve dinleyebilir. Bu özellik genellikle insan etkileşimlerini veya diğer dış tetikleyicileri işlemek için kullanışlıdır.

Uyarı

Dış olaylar tek yönlü asenkron işlemlerdir. Olayı gönderen istemcinin orkestrasyondan senkron bir yanıt alması gerektiği durumlar için uygun değildir.

Önemli

Şu anda PowerShell Dayanıklı Görev SDK'sı kullanılamıyor.

Dış olayları bekleme

Düzenleme tetikleyicisi bağlamasının"wait-for-external-event" API'si, bir düzenleyici işlevinin zaman uyumsuz olarak bir dış istemci tarafından teslim edilen bir olayı beklemesine ve dinlemesine olanak tanır. Dinleme düzenleyici işlevi olayın adını ve almayı beklediği verilerin şeklini bildirir.

"Wait-for-external-event" API'si, bir düzenlemenin zaman uyumsuz olarak bir dış istemci tarafından teslim edilen bir olayı beklemesine ve dinlemesine olanak tanır. Dinleme düzenlemesi olayın adını ve almayı beklediği verilerin şeklini bildirir.

Yalıtılmış çalışan modeli

using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
using Microsoft.Extensions.Logging;

public class BudgetApproval
{
    private readonly ILogger _logger;

    public BudgetApproval(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<BudgetApproval>();
    }

    [Function("BudgetApproval")]
    public async Task Run(
        [OrchestrationTrigger] TaskOrchestrationContext context)
    {
        bool approved = await context.WaitForExternalEventAsync<bool>("Approval");
        if (approved)
        {
            // approval granted - do the approved action
        }
        else
        {
            // approval denied - send a notification
        }
    }
}

İşlem içi model

[FunctionName("BudgetApproval")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool approved = await context.WaitForExternalEvent<bool>("Approval");
    if (approved)
    {
        // approval granted - do the approved action
    }
    else
    {
        // approval denied - send a notification
    }
}

Uyarı

Dayanıklı İşlevler 1.x kullanıyorsanız, DurableOrchestrationContext yerine IDurableOrchestrationContext kullanın. Sürümlere özgü ayrıntılar için Dayanıklı İşlevler sürümleri makalesine göz atın.

public class BudgetApproval : TaskOrchestrator<object?, bool>
{
    public override async Task<bool> RunAsync(TaskOrchestrationContext context, object? input)
    {
        bool approved = await context.WaitForExternalEvent<bool>("Approval");
        if (approved)
        {
            // approval granted - do the approved action
        }
        else
        {
            // approval denied - send a notification
        }
        return approved;
    }
}

Yukarıdaki örnek, belirli bir olayı dinler ve olay alındığında işlem yapar.

Aşağıdaki örnekte olduğu gibi, üç olası olay bildiriminden birini bekleyen birden çok olayı eşzamanlı olarak dinleyebilirsiniz.

Yalıtılmış çalışan modeli

[Function("Select")]
public async Task Run(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    Task<float> event1 = context.WaitForExternalEventAsync<float>("Event1");
    Task<bool> event2 = context.WaitForExternalEventAsync<bool>("Event2");
    Task<int> event3 = context.WaitForExternalEventAsync<int>("Event3");

    Task winner = await Task.WhenAny(event1, event2, event3);
    if (winner == event1)
    {
        // ...
    }
    else if (winner == event2)
    {
        // ...
    }
    else if (winner == event3)
    {
        // ...
    }
}

İşlem içi model

[FunctionName("Select")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var event1 = context.WaitForExternalEvent<float>("Event1");
    var event2 = context.WaitForExternalEvent<bool>("Event2");
    var event3 = context.WaitForExternalEvent<int>("Event3");

    var winner = await Task.WhenAny(event1, event2, event3);
    if (winner == event1)
    {
        // ...
    }
    else if (winner == event2)
    {
        // ...
    }
    else if (winner == event3)
    {
        // ...
    }
}

Uyarı

Dayanıklı İşlevler 1.x mi kullanıyorsunuz? DurableOrchestrationContext yerine IDurableOrchestrationContext değiştirin. Diğer sürüm farklılıkları hakkında bilgi edinmek için Dayanıklı İşlevler sürümleri makalesine bakın.

public class SelectOrchestrator : TaskOrchestrator<object?, object?>
{
    public override async Task<object?> RunAsync(TaskOrchestrationContext context, object? input)
    {
        Task<float> event1 = context.WaitForExternalEvent<float>("Event1");
        Task<bool> event2 = context.WaitForExternalEvent<bool>("Event2");
        Task<int> event3 = context.WaitForExternalEvent<int>("Event3");

        Task winner = await Task.WhenAny(event1, event2, event3);
        if (winner == event1)
        {
            // ...
        }
        else if (winner == event2)
        {
            // ...
        }
        else if (winner == event3)
        {
            // ...
        }
        return null;
    }
}

Önceki örnek birden çok olaydan herhangi birini dinler. Ayrıca tüm olayları da bekleyebilirsiniz.

Yalıtılmış çalışan modeli

[Function("NewBuildingPermit")]
public async Task Run(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    string applicationId = context.GetInput<string>();

    Task gate1 = context.WaitForExternalEventAsync<object>("CityPlanningApproval");
    Task gate2 = context.WaitForExternalEventAsync<object>("FireDeptApproval");
    Task gate3 = context.WaitForExternalEventAsync<object>("BuildingDeptApproval");

    // all three departments must grant approval before a permit can be issued
    await Task.WhenAll(gate1, gate2, gate3);

    await context.CallActivityAsync("IssueBuildingPermit", applicationId);
}

İşlem içi model

[FunctionName("NewBuildingPermit")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string applicationId = context.GetInput<string>();

    var gate1 = context.WaitForExternalEvent("CityPlanningApproval");
    var gate2 = context.WaitForExternalEvent("FireDeptApproval");
    var gate3 = context.WaitForExternalEvent("BuildingDeptApproval");

    // all three departments must grant approval before a permit can be issued
    await Task.WhenAll(gate1, gate2, gate3);

    await context.CallActivityAsync("IssueBuildingPermit", applicationId);
}

Uyarı

Dayanıklı İşlevler 1.x çalıştırıyorsanız DurableOrchestrationContext yerine IDurableOrchestrationContext kullanın. Sürüm farklılıklarının tam dökümü için Dayanıklı İşlevler sürümlerine gidin.

.NET'te, olay yükü beklenen türe Tdönüştürülemiyorsa bir özel durum oluşturulur.

public class NewBuildingPermit : TaskOrchestrator<string, object?>
{
    public override async Task<object?> RunAsync(TaskOrchestrationContext context, string applicationId)
    {
        Task<object?> gate1 = context.WaitForExternalEvent<object?>("CityPlanningApproval");
        Task<object?> gate2 = context.WaitForExternalEvent<object?>("FireDeptApproval");
        Task<object?> gate3 = context.WaitForExternalEvent<object?>("BuildingDeptApproval");

        // all three departments must grant approval before a permit can be issued
        await Task.WhenAll(gate1, gate2, gate3);

        await context.CallActivityAsync("IssueBuildingPermit", applicationId);
        return null;
    }
}

.NET'te, olay yükü beklenen türe Tdönüştürülemiyorsa bir özel durum oluşturulur.

"Wait-for-external-event" API'sinin bazı girişler için süresiz olarak beklemesi gerekir. Beklerken işlev uygulamasını güvenle kaldırabilirsiniz. Eğer ve ne zaman bu düzenleme örneği için bir olay gelirse, örnek otomatik olarak uyandırılır ve olayı anında işler.

Uyarı

İşlev uygulamanız Tüketim Planı'nı kullanıyorsa, düzenleyici işlevi ne kadar beklerse beklesin bir dış olay görevi beklerken faturalama ücreti uygulanmaz.

Etkinlik İşlevleri'nde olduğu gibi dış olaylarda en az bir kez teslim garantisi vardır. Bu, belirli koşullar altında (yeniden başlatmalar, ölçeklendirme, kilitlenmeler vb.) uygulamanızın aynı dış olayın tekrarlarını alabileceği anlamına gelir. Bu nedenle, dış olayların düzenleyicilerde el ile yinelenmesini önleyecek bir tür kimlik içermesini öneririz.

"Wait-for-external-event" API'sinin bazı girişler için süresiz olarak beklemesi gerekir. Beklerken çalışanı güvenle durdurabilirsiniz. Bu düzenleme örneği için bir olay gelmesi hâlinde, düzenleme otomatik olarak uyanır ve olayı hemen işler.

Dış olaylar için en az bir kez teslimat garantisi vardır. Bu, belirli koşullar altında (yeniden başlatmalar, ölçeklendirme, kilitlenmeler vb.) uygulamanızın aynı dış olayın tekrarlarını alabileceği anlamına gelir. Bu nedenle, dış olayların düzenlemelerde el ile çoğaltılmasını sağlayan bir tür kimlik içermesini öneririz.

Olayları gönderme

Orkestrasyon istemci bağlaması tarafından tanımlanan "raise-event" API'sini kullanarak bir orkestrasyona dış bir olay gönderebilirsiniz. Ayrıca, bir düzenlemeye dış olay göndermek için yerleşik olarak sunulan olay tetikleme HTTP API'sini de kullanabilirsiniz.

Tetiklenen olay parametre olarak bir instanceID, bir eventName, ve bir eventData içerir. Orchestrator işlevleri API'leri wait-for-external-event kullanarak bu olayları işler. Hem eventName hem de alan uçlarında eşleşmelidir ki olay işlenebilsin. Olay verileri de JSON serileştirilebilir olmalıdır.

Dahili olarak "raise-event" mekanizmaları, bekleyen orchestrator fonksiyonu tarafından alınmak üzere bir iletiyi kuyruğa alır. Örnek belirtilen olay adını beklemiyorsa, olay iletisi bellek içi kuyruğa eklenir. Orkestrasyon örneği daha sonra bu olay adını dinlemeye başlarsa, olay iletileri için kuyruğu denetler.

Uyarı

Belirtilen örnek kimliğine sahip bir düzenleme örneği yoksa, olay iletisi atılır.

Aşağıda, bir orkestratör işlevi örneğine "Onay" etkinliğini gönderen, kuyrukla tetiklenen bir işlev örneği bulunmaktadır. Orkestrasyon örnek kimliği, kuyruk mesajının gövdesinden gelir.

Bir orkestrasyona dış olay göndermek için Dayanıklı Görev istemcisinde "raise-event" API'sini kullanabilirsiniz.

Tetiklenen olay parametre olarak bir örnek kimliği, eventName ve eventData içerir. Orkestrasyonlar, bu olayları "wait-for-external-event" API'lerini kullanarak işler. Olayın işlenmesi için eventName öğesinin hem gönderen hem de alan uçlarda eşleşmesi gerekir. Olay verileri de JSON serileştirilebilir olmalıdır.

Dahili olarak "raise-event" mekanizmaları, bekleyen orkestrasyon tarafından alınacak bir iletiyi sıraya alır. Örnek belirtilen olay adını beklemiyorsa, olay iletisi bellek içi kuyruğa eklenir. Orkestrasyon örneği daha sonra bu olay adını dinlemeye başlarsa, olay iletileri için kuyruğu kontrol eder.

Uyarı

Belirtilen instanceID ile orkestrasyon örneği yoksa, olay iletisi atılır.

Aşağıda, bir düzenleme örneğine "Onay" olayı gönderen bir örnek verilmiştir.

Yalıtılmış çalışan modeli

using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask.Client;

public class ApprovalQueueProcessor
{
    [Function("ApprovalQueueProcessor")]
    public async Task Run(
        [QueueTrigger("approval-queue")] string instanceId,
        [DurableClient] DurableTaskClient client)
    {
        await client.RaiseEventAsync(instanceId, "Approval", true);
    }
}

İşlem içi model

[FunctionName("ApprovalQueueProcessor")]
public static async Task Run(
    [QueueTrigger("approval-queue")] string instanceId,
    [DurableClient] IDurableOrchestrationClient client)
{
    await client.RaiseEventAsync(instanceId, "Approval", true);
}

Uyarı

Dayanıklı İşlevler 1.x için OrchestrationClient özniteliğini ve bunun yerine DurableOrchestrationClient parametre türünü kullanın. Sürüme özgü tüm değişiklikler için Dayanıklı İşlevler sürümleri makalesini inceleyin.

await client.RaiseEventAsync(instanceId, "Approval", true);

Dahili olarak, "raise-event" API'si, bekleyen düzenleme tarafından teslim alınacak bir mesajı sıraya alır. Örnek belirtilen olay adını beklemiyorsa, olay iletisi bellek içi arabelleğe eklenir. Eğer orkestrasyon örneği daha sonra bu olay adını dinlemeye başlarsa, olay iletileri için arabelleği kontrol eder ve bekleyen görevi tetikler.

Uyarı

Belirtilen örnek kimliğine sahip bir düzenleme örneği yoksa, olay iletisi atılır.

HTTP

Aşağıda, bir olayı düzenleme örneğine yükselten Approval bir HTTP isteği örneği verilmiştir.

POST /runtime/webhooks/durabletask/instances/MyInstanceId/raiseEvent/Approval&code=XXX
Content-Type: application/json

"true"

Bu durumda örnek kimliği MyInstanceId olarak sabit kodlanır.

En iyi uygulamalar

Dış olaylarla çalışırken aşağıdaki en iyi yöntemleri göz önünde bulundurun:

Deduplikasyon için benzersiz olay adlarını kullanma

Dış olaylar için en az bir kez teslimat garantisi vardır. Bazı nadir koşullarda (yeniden başlatmalar, ölçeklendirme veya kilitlenmeler sırasında oluşabilir), uygulamanız aynı dış olayın yinelenenlerini alabilir. Harici olayların, orkestratörlerde manuel olarak çoğaltmaları önleyen benzersiz bir kimlik içermesini öneririz.

Uyarı

MSSQL depolama sağlayıcısı dış olayları tüketir ve orchestrator durumunu işlemsel olarak günceller; bu nedenle, Azure Depolama sağlayıcısından farklı olarak, bu arka uç ile yinelenen olaylar riski yoktur. Ancak, kodun arka uçlar arasında taşınabilir olması için dış olayların benzersiz adlara sahip olması önerilir.

Süresiz beklemeleri önlemek için zaman aşımlarını kullanma

wait-for-external-event API varsayılan olarak süresiz olarak bekler. İnsan onayları gibi gerçek dünya senaryolarının çoğunda, etkinliğin son tarihe kadar ulaşmaması durumunda düzenlemenizin eylem gerçekleştirmesi (yükseltme, reddetme, yeniden deneme) için dayanıklı bir süreölçerle dış olaya karşı yarışmalısınız.

Kod örnekleriyle ilgili eksiksiz bir kılavuz için bkz. İnsan etkileşimi ve zaman aşımları.

Sonraki Adımlar