Logic apps and Azure functions are best suited for serverless architecture, but, if you have requirement of long-running jobs, let say up to 10minutes, it is acceptable for Azure functions. This is because, functions can run for 10 minutes, but logic app waits only for 2 minutes for HTTP requests. If logic app doesn’t get any response within 2 minutes, the request will timeout and retries again (number of retries can be configured from logic app). This will never go to next step.
This can be solved with 2 approaches:
- Webhook with queue messaging
- Durable Azure functions (this is stable V2 Azure functions)
In this article, I will be explaining the 1st approach.
How it works:
- The HTTP trigger Azure function will be called from logic app with a callback URL. (with webhook action)
- HTTP trigger function will drop a message in the queue and returns the response to the logic app. Now, logic app thinks that the request is processing and waits until the callback URL is called.
- As soon as a message is added in the queue, the queue trigger Azure function will be triggered. It will do the long running job and sends a response to the logic app. Once logic app gets a response, it will go to the next step.
How can this be achieved?
Step1:
Create a logic app and HTTP trigger Azure function and call the HTTP trigger function from logic app using webhook action. See the image below:
Step 2:
Configure the HTTP trigger Azure function output queue item. (function-> integrate->outputs)
Now drop a message in the queue which can be read in the “queue trigger Azure function”, find the below sample code.
using System.Net;
using System;
public static async Task<HttpResponseMessage>
Run(HttpRequestMessage req, TraceWriter log,ICollector<ProcessRequest> outputQueueItem)
{
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
log.Info("data is "+data);
TestObj testData = new TestObj {
Title = data.Title,
Description = data.Description
};
string callbackUrl = data?.callbackUrl;
log.Info("Call back url"+callbackUrl);
outputQueueItem.Add(new ProcessRequest { callbackUrl = callbackUrl, TestData = testData });
return req.CreateResponse(HttpStatusCode.OK, "test request received");
}
public class ProcessRequest
{
public string callbackUrl { get; set; }
public TestObj TestData { get; set; }
}
public class TestObj {
public string Title { set; get; }
public string Description { get; set; }
}
———————————————————————————————————————————-
Step 3:
Configure the “queue trigger azure function” trigger,(function->integrate->triggers)
Sample code for queue trigger:
#r "Newtonsoft.Json.dll"
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using System.Net;
using System.Web.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public static void Run([QueueTrigger("siteprovqueue")]ProcessRequest item, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {item}");
try{
//Thread.Sleep(TimeSpan.FromMinutes(3));
// your functionality goes here
ProcessResponse response = new ProcessResponse() { Test = “Test” }
string json = JsonConvert.SerializeObject(response);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(item.callbackUrl);
req.Method = "POST";
req.ContentType = "application/json";
Stream stream = req.GetRequestStream();
byte[] buffer = Encoding.UTF8.GetBytes(json);
stream.Write(buffer,0, buffer.Length);
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
}
catch(Exception ex){
// log.Info(ex.Message);
// log.Info(ex.InnerException.Message);
}
}
public class ProcessResponse
{
public string siteUrl { get; set; }
}