Vi har tidigare publicerat en artikel om att BizTalks end-of-life närmar sig med stormsteg och vilka möjligheter det finns att ersätta sin implementation med lämpliga Azure-resurser. I denna artikel går vi lite mer på djupet med ett konkret exempel på hur man kan hantera och ersätta long running transaction med hjälp av Azure Functions
Vi har tidigare publicerat en artikel om att BizTalks end-of-life närmar sig med stormsteg och vilka möjligheter det finns att ersätta sin implementation med lämpliga Azure-resurser.
I denna artikel går vi lite mer på djupet med ett konkret exempel på hur man kan hantera och ersätta long running transaction med hjälp av Azure Functions.
I BizTalk används Orchestrations för att hantera arbetsflöden där meddelanden behandlas över längre tid, exempelvis en inköpsorder som väntar på en bekräftelse innan den går vidare.
I Azure kan vi uppnå samma funktionalitet med Azure Durable Functions, där vi använder orchestrator functions för att hantera arbetsflöden med tillståndshantering och activity functions för enskilda uppgifter.
Exempel: Inköpsorder med bekräftelse
Föreställ dig ett scenario där en inköpsorder tas emot, vidarebefordras till ett externt system och sedan inväntar en bekräftelse innan den skickas vidare till nästa mottagare.
I BizTalk kan detta hanteras med en orchestration som:
- Tar emot inköpsorder
- Skickar den vidare till ett externt system
- Väntar på en bekräftelse (med correlation)
- Vid bekräftelse, uppdaterar och vidarebefordrar meddelandet
I Azure Durable Functions kan vi återskapa detta med en http trigger function som startar flödet genom att ta emot en inköpsorder, en orchestrator function som koordinerar flödet och activity functions för att hantera varje steg. Nedan visar hur en sådan implementation kan se ut.
Durable Functions-implementation
Implementationen består av 6 stycken functions enligt nedan.
- StartPurchaseOrderOrchestration – HTTP-trigger för att starta processen.
- PurchaseOrderOrchestrator – Huvudprocessen som hanterar orderflödet.
- SendOrder – Activity Function som skickar ordern vidare för bekräftelse.
- ConfirmOrder – HTTP-trigger som tar emot den bekräftade ordern.
- ForwardConfirmedOrder – Activity Function som skickar vidare en bekräftad order.
- HandleTimeout – Activity Function som hanterar timeout om ingen bekräftelse kommer.
Här följer koden för implementationen. Den går även att ladda ner här från GitHub.
Start orchestration function
Detta är är start punkten för processen. En Inköpsorder skickas in och Orchestrator-funktionen meddelas att starta en ny process.
[Function("StartPurchaseOrderOrchestration")]
public async Task<HttpResponseData> Start(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
[DurableClient] DurableTaskClient client,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("StartPurchaseOrderOrchestration");
// Läs in ordern från HTTP-requestens body
var order = await req.ReadFromJsonAsync<PurchaseOrder>();
order.Status = "Pending";
if (order == null)
{
var badRequest = req.CreateResponse(HttpStatusCode.BadRequest);
await badRequest.WriteStringAsync("Invalid request payload");
return badRequest;
}
// Starta orchestratorn
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("PurchaseOrderOrchestrator", order);
logger.LogInformation($"Orchestrator startad med Instance ID: {instanceId}, order status: {order.Status}");
// Skapa en response med URL:er för att kolla status
var response = req.CreateResponse(HttpStatusCode.Accepted);
var statusQueryUri = $"{req.Url.GetLeftPart(UriPartial.Authority)}/runtime/webhooks/durabletask/instances/{instanceId}";
response.Headers.Add("Location", statusQueryUri);
await response.WriteStringAsync($"Orchestration started. Instance ID: {instanceId}");
return response;
}
}
Orchestrator function
Denna Function hanterar hela flödet och anropar i sin tur Activity Functions för att utföra olika uppgifter och väntar i sin tur på svar.
Här triggas först funktionen SendOrder som i sin tur skickar en fiktiv inköpsordet till ett externt system. En deadline på 24 timmar skapas som väntar på att ordern ska bekräftas. När eller om det kommer en bekräftelse så skickas meddelandet vidare via funktionen ForwardConfirmedOrder.
Skulle det inte komma en bekräftelse inom utsatt tid triggas HandleTimeOut som i sin tur kan innehålla logik för att hantera scenariot.
[Function("PurchaseOrderOrchestrator")]
public async Task RunOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
var order = context.GetInput<PurchaseOrder>();
// Skicka ordern vidare
await context.CallActivityAsync("SendOrder", order);
// Vänta på bekräftelse i upp till 24 timmar
DateTime deadline = context.CurrentUtcDateTime.AddHours(24);
Task timeoutTask = context.CreateTimer(deadline, CancellationToken.None);
Task<string> confirmationTask = context.WaitForExternalEvent<string>("OrderConfirmed");
Task completedTask = await Task.WhenAny(confirmationTask, timeoutTask);
if (completedTask == confirmationTask)
{
// Bekräftelse mottagen, skicka vidare
order.Status = "Confirmed";
await context.CallActivityAsync("ForwardConfirmedOrder", confirmationTask.Result);
}
else
{
order.Status = "TimedOut";
// Timeout inträffade, hantera felet
await context.CallActivityAsync("HandleTimeout", order);
}
}
Activity functions
[Function("SendOrder")]
public async Task SendOrder([ActivityTrigger] PurchaseOrder order, FunctionContext executionContext)
{
var logger = executionContext.GetLogger("SendOrder");
order.Status = "SentForConfirmation";
logger.LogInformation($"Skickar inköpsorder {order.Id}, status: {order.Status}");
// Simulerat API-anrop till externt system
}
[Function("ForwardConfirmedOrder")]
public async Task ForwardConfirmedOrder([ActivityTrigger] string confirmation, FunctionContext executionContext)
{
var logger = executionContext.GetLogger("ForwardConfirmedOrder");
logger.LogInformation($"Order bekräftad: {confirmation}, skickar vidare.");
}
[Function("HandleTimeout")]
public async Task HandleTimeout([ActivityTrigger] PurchaseOrder order, FunctionContext executionContext)
{
var logger = executionContext.GetLogger("HandleTimeout");
logger.LogWarning($"Timeout för order {order.Id}, ingen bekräftelse mottagen.");
}
Orderbekräftelse function
Bekräftelsen kommer in via en HTTP-trigger och signalerar orchestratorn att ordern är bekräftat.
[Function("ConfirmOrder")]
public async Task<HttpResponseData> ConfirmOrder(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
[DurableClient] DurableTaskClient client,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("ConfirmOrder");
string instanceId = req.Query["instanceId"];
string confirmation = await new StreamReader(req.Body).ReadToEndAsync();
await client.RaiseEventAsync(instanceId, "OrderConfirmed", confirmation);
logger.LogInformation($"Bekräftelse mottagen för {instanceId}");
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync("Order confirmed");
return response;
}
Varför Durable Functions?
Med Durable Functions får vi en stateful orchestration utan att behöva hantera en separat message broker eller databaser för att hålla koll på transaktionens status. Lösningen är serverless, vilket innebär att vi slipper underhåll av infrastruktur och kan dra nytta av automatisk skalning.
I och med att orchestratorn hanterar timeouts och externa event kan vi enkelt bygga in robust felhantering, något som i BizTalk kräver mer komplex konfiguration.
Har ni frågor om hur ni kan migrera från BizTalk till Azure? Hör av er så pratar vi vidare! 🚀

Skriven av
Markus Lundberg
Läs mer om Data & Integrations

Azure Integration Services, nyckeln till moderna integrationer
Många företag står med ena benet i äldre system och det andra i moln- och AI-världen. Hur bygger man en sömlös bro mellan dessa två utan att fastna i komplexa integrationsprojekt? I denna artikeln om Azure Integration Services visar vi hur Microsofts integrerade verktygslåda ger dig kraften att automatisera processer, exponera API:er och skapa eventstyrda flöden med robust säkerhet och skalbarhet.
Läs mer
Azure Events, hur man tar kontroll över sin Azure-miljö.
Vill du ha bättre koll på vad som händer i din Azure-miljö, i realtid? Läs om hur du kan få bättre kontroll på ändringar i din miljö. Vem skapar nya resurser? Finns det något certifikat som snart är expired, etc? Med Azure Events kan du dessutom automatiskt ta actions på när saker händer!
Läs mer
Nyheterna i C# 14 och .NET 10
I november släpps .NET 10 tillsammans med C# 14. En LTS release som kommer med en del roliga nyheter. I denna artikeln går vi igenom vad som är nytt och bra att veta.
Läs mer