I'm trying to implement an API that performs some really lengthy tasks using a Web Service. I basically want the Web Service to kick off a thread that performs the lengthy task and leaves it running until it completes. The issue is because its an API I want it to be cross-platform. So my questions are the following:
Okay, back up a second.
If you want people to be able to call asynch, then they control and you just respond. If you want asynch work to be done on your side, then you need to institute a different pattern. One pattern is to set up a method that calls the work and then another method to see the status of the work. The first method returns some type of token/id that can be used to check the status on the other call. You then have a third method to pick up the results. This is all client driven.
You can, in theory, set up a callback mechanism, but the client needs to have a means of getting the answer, which is a service on their side. This is more complex, and less "public API" in nature, but it can work with clients.
The heterogenous nature of the system should not be a factor. And, you can institute both patterns, so clients that have a web service that can take the answer can fire and forget, while others poll.
The one downside of polling is you add more weight to your side, so set proper expectations and be prepared to throttle the guy that does something like this:
while(thread.NoComplete())
{
pollTheCrapOutofService();
}
If you can get around heterogenous environs (open standards, et al), and can force .NET, you have other options, as Craig has mentioned.
This is a good place to start:
http://msdn.microsoft.com/en-us/library/aa480516.aspx
If you implement this pattern, from the client perspective, nothing changes. You can implement a second web method to check the status of any running jobs you queue up in your async method.
From the sample code, modified somewhat to give you an idea of what you need to do (I don't expect this would compile):
[WebService]
public class AsyncWebService : System.Web.Services.WebService
{
public delegate string LengthyProcedureAsyncStub(
int milliseconds, MyState state);
public string LengthyProcedure(int milliseconds, MyState state)
{
while(state.Abort == false)
{
//Do your work. Check periodically for an abort
}
return state.Abort ? "Aborted" : "Success";
}
//This state object is what you can use to track invocations of your method
//You'll need to store it in a thread safe container. Add it to the container in the Begin method and remove it in the end method. While it's in the container other web methods can find it and use it to monitor or stop the executing job.
public class MyState
{
public Guid JobID = Guid.NewGuid();
public object previousState;
public LengthyProcedureAsyncStub asyncStub;
public bool Abort = false;
}
[ System.Web.Services.WebMethod ]
public IAsyncResult BeginLengthyProcedure(int milliseconds,
AsyncCallback cb, object s)
{
LengthyProcedureAsyncStub stub
= new LengthyProcedureAsyncStub(LengthyProcedure);
MyState ms = new MyState();
ms.previousState = s;
ms.asyncStub = stub;
//Add to service wide container
return stub.BeginInvoke(milliseconds, cb, ms);
}
[ System.Web.Services.WebMethod ]
public string EndLengthyProcedure(IAsyncResult call)
{
//Remove from service wide container
MyState ms = (MyState)call.AsyncState;
return ms.asyncStub.EndInvoke(call);
}
[WebMethod]
public void StopJob(Guid jobID)
{
//Look for the job in the service wide container
MyState state = GetStateFromServiceWideContainer(jobID);
state.Abort = true;
}
}
As far as the client is concerned, they are calling a webmethod called LenghtyProcedure that will not return until the job is complete.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With