Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise comments #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions AsyncResponse/Controllers/AsyncController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,67 +13,67 @@ namespace AsyncResponse.Controllers
{
public class AsyncController : ApiController
{
//State dictionary for sample - stores the state of the working thread
// Create a state dictionary that stores the state for the working thread in this sample
private static Dictionary<Guid, bool> runningTasks = new Dictionary<Guid, bool>();


/// <summary>
/// This is the method that starts the task running. It creates a new thread to complete the work on, and returns an ID which can be passed in to check the status of the job.
/// In a real world scenario your dictionary may contain the object you want to return when the work is done.
/// This method starts the task, creates a new thread to do work,
/// and returns an ID that you can pass to the Logic Apps engine for checking job status.
/// In a real world scenario, your dictionary can contain the object that you want to return after work has finished.
/// </summary>
/// <returns>HTTP Response with needed headers</returns>
[HttpPost]
[Route("api/startwork")]
public async Task<HttpResponseMessage> longrunningtask()
{
Guid id = Guid.NewGuid(); //Generate tracking Id
runningTasks[id] = false; //Job isn't done yet
new Thread(() => doWork(id)).Start(); //Start the thread of work, but continue on before it completes
Guid id = Guid.NewGuid(); // Generate tracking ID for checking job status
runningTasks[id] = false; // Job not done yet
new Thread(() => doWork(id)).Start(); // Start the thread to do work, but continue on before the job completes
HttpResponseMessage responseMessage = Request.CreateResponse(HttpStatusCode.Accepted);
responseMessage.Headers.Add("location", String.Format("{0}://{1}/api/status/{2}", Request.RequestUri.Scheme, Request.RequestUri.Host, id)); //Where the engine will poll to check status
responseMessage.Headers.Add("retry-after", "20"); //How many seconds it should wait (20 is default if not included)
responseMessage.Headers.Add("location", String.Format("{0}://{1}/api/status/{2}", Request.RequestUri.Scheme, Request.RequestUri.Host, id)); // The URL to poll for job status
responseMessage.Headers.Add("retry-after", "20"); // The number of seconds to wait before polling for job status again. The default is 20 seconds when not included.
return responseMessage;
}


/// <summary>
/// This is where the actual long running work would occur.
/// This method performs the actual long-running work.
/// </summary>
/// <param name="id"></param>
private void doWork(Guid id)
{
Debug.WriteLine("Starting work");
Task.Delay(120000).Wait(); //Do work will work for 120 seconds)
Task.Delay(120000).Wait(); // Do work for 120 seconds.
Debug.WriteLine("Work completed");
runningTasks[id] = true; //Set the flag to true - work done
runningTasks[id] = true; // Set flag to "true" when work is done.
}

/// <summary>
/// Method to check the status of the job. This is where the location header redirects to.
/// This method checks the job's status and is also the place to where the "location" header redirects.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
[Route("api/status/{id}")]
[Swashbuckle.Swagger.Annotations.SwaggerResponse(HttpStatusCode.BadRequest, "No job exists with the specified id")]
[Swashbuckle.Swagger.Annotations.SwaggerResponse(HttpStatusCode.BadRequest, "No job exists with the specified ID")]
[Swashbuckle.Swagger.Annotations.SwaggerResponse(HttpStatusCode.Accepted, "The job is still running")]
[Swashbuckle.Swagger.Annotations.SwaggerResponse(HttpStatusCode.OK, "The job has completed")]
public HttpResponseMessage checkStatus([FromUri] Guid id)
{
//If the job is complete
// If the job is done, return "200 OK" status with response payload (data output).
if(runningTasks.ContainsKey(id) && runningTasks[id])
{
runningTasks.Remove(id);
return Request.CreateResponse(HttpStatusCode.OK, "Some data could be returned here");
return Request.CreateResponse(HttpStatusCode.OK, "Can return some data here");
}
//If the job is still running
// If the job is still running, return "202 ACCEPTED" status, the URL to poll for job status, and the number of seconds to wait before checking status again.
else if(runningTasks.ContainsKey(id))
{
HttpResponseMessage responseMessage = Request.CreateResponse(HttpStatusCode.Accepted);
responseMessage.Headers.Add("location", String.Format("{0}://{1}/api/status/{2}", Request.RequestUri.Scheme, Request.RequestUri.Host, id)); //Where the engine will poll to check status
responseMessage.Headers.Add("location", String.Format("{0}://{1}/api/status/{2}", Request.RequestUri.Scheme, Request.RequestUri.Host, id)); // The URL where the engine can poll for job status
responseMessage.Headers.Add("retry-after", "20");
return responseMessage;
}
// No job with the specified ID was found.
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "No job exists with the specified ID");
Expand Down
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
[![Deploy to Azure](http://azuredeploy.net/deploybutton.png)](https://azuredeploy.net/)

# Logic Apps Async Response Sample
Sample of how to do an HTTP Async Response pattern to work with Azure Logic Apps. See the AsyncController for the logic. The Logic Apps engine will timeout by default after 1-2 minutes of an open HTTP Request. By setting up this async pattern you can keep the Logic Apps engine waiting for a task for much longer (as long as you have data stored for your flow - which is up to 1 year for Premium plans).

## How it Works ##
This sample shows how to create an HTTP Async Response pattern that works for Azure Logic Apps.
For logic details, see the AsyncController.cs file. By default, the Logic Apps engine times out
after 1-2 minutes for an open HTTP Request. When you set up this async pattern,
you can make the Logic Apps engine wait for a task that takes longer to finish
(as long as you have data stored for your flow, which is up to 1 year for Premium plans).

When you get the initial request to start work, you start a thread with the long-running task, and immediatly return an HTTP Response "202 Accepted" with a location header. The location header points to the URL for the Logic Apps to check the status of the long-running job. By default the engine will check every 20 seconds, but you can also add a "Retry-after" header to specify the amount of seconds until the next poll.
## How the sample works

After the alloted time (20 seconds), the engine will poll the URL on the location header. If the long-running job is still going, you should return another "202 Accepted" with a location header. If the job has completed, you should return a "200 OK", along with any relevant data. This is what the Logic Apps engine will continue the workflow with.
When you get the initial request to start work, start a thread with the long-running task,
and immediatly return an HTTP Response "202 Accepted" status with a location header.
The location header points to the URL where the Logic Apps engine can check status for the long-running job.

By default, the engine checks every 20 seconds, but you can also add a "Retry-after" header
that specifies the number of seconds until the next poll. After the given time (20 seconds),
the engine polls the URL on the location header. If the long-running job is still working,
you should return another "202 Accepted" status with a location header.
If the job has finished, you should return a "200 OK" status, along with any relevant data.
The Logic Apps engine uses this data to continue the workflow.