- Vårt erbjudande
- Kundcase
- Insikter & Inspiration
- Om oss

Hem/Insikter & Inspiration/BizTalk-migrering i praktiken – steg för steg med Azure Durable Functions
BizTalk-migrering i praktiken – steg för steg med Azure Durable Functions
/ Data & Integrations /
BizTalk-migrering i praktiken – steg för steg med Azure Durable 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 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();
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();
// 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 confirmationTask = context.WaitForExternalEvent("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 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! 🚀
