I've read myself blue and am hoping there's a simple answer.
I have a web API that handles telemetry from various apps "in the wild" In one of my controllers, I want to receive a request to log an error to my central monitoring database and return a response near immediately as possible (I have no real way of knowing how critical performance might be on the caller's end and there's already a significant hit for making the initial web service request).
Essentially, what I'm looking for is something like this:
public IHttpActionResult Submit() {
try {
var model = MyModel.Parse(Request.Content.ReadAsStringAsync().Result);
// ok, I've got content, now log it but don't wait
// around to see the results of the logging, just return
// an Accepted result and begone
repository.SaveSubmission(model); // <-- fire and forget, don't wait
return Accepted();
} catch (Exception)
return InternalServerError();
}
}
It seems like it ought to be straightforward, but apparently not. I've read any number of various posts indicating everything from yup, just use Task.Run() to this is a terrible mistake and you can never achieve what you want!
The problem in my scenario appears to be the fact that this process could be terminated mid-process due to it running on the ASP.NET worker process, regardless of the mire of different ways to invoke async methods (I've spend the last two hours or so reading various SO questions and Stephen Cleary blogs... whew).
If the underlying issue in this case is that the method I'd 'fire and forget' is bound to the http context and subject to early termination by the ASP.NET worker process, then my question becomes...
Is there some way to remove this method/task/process from that ASP.NET context? Once that request is parsed into the model, I myself have no more specific need to be operating within the http context. If there's an easy way I can move it out of there (and thus letting the thing run barring a website/apppool restart), that'd be great.
For the sake of due diligence, let's say I get rid of the repository context in the controller and delegate it to some other context:
public IHttpActionResult Submit() {
try {
var model = MyModel.Parse(Request.Content.ReadAsStringAsync().Result);
SomeStaticClass.SaveSubmission(model); // <-- fire and forget, don't wait
return Accepted();
} catch (Exception)
return InternalServerError();
}
}
... then the only thing that has to "cross lines" is the model itself - no other code logic dependencies.
Granted, I'm probably making a mountain of a molehill - the insertion to the database won't take but a fraction of time anyway... it seems like it should be easy though, and I'm apparently too stubborn to settle for "good enough" tonight.