BackgroundService not blocking start of application - c#

I have a background service in my net 7 web api application:
public class MyBackgroundService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using var scope = _provider.CreateScope();
// do some work
await Task.Delay(60000, stoppingToken);
}
}
}
Which I register like this:
services.AddHostedService<MyBackgroundService>();
How can I make it blocking so that the rest of my application doesn't start before the first do some work is executed?

It depends on how your application is wired. If you are using the default setup (for ASP.NET Core 7th version) then background services should be started up before the rest of the app and you can just override the BackgroundService.StartAsync (or just implement IHostedService directly) and perform first "do some work code" (potentially moving it to separate method) invocation in blocking manner (i.e. use blocking calls via Task.Result or Task.Wait(...) for async methods). Also do not forget to register this "blocking" hosted service first if you have multiple ones.
If you do not want to rely on the default order or you are using setup which has different order of startup (for example see this) then I would recommend to move the "do some work code" in some service, resolve it and invoke it before the app run:
var app = builder.Build();
// ...
var service = app.Services.GetRequiredService<IMyService>(); // create scope if needed
await service.DoSomeWorkCode(); // first run
app.Run();
P.S.
Also you can consider adding readiness probe to your app and middleware which will intercept all other requests if app is not ready (i.e. the initial run of "do some work code" has not finished).

Move the
// do some work code
into a separate method so you can call it at startup.

Related

alternative for System.Web.Hosting.HostingEnvironment.RegisterObject in asp.net core 2.0

I have a legacy application where HostingEnivronment.RegisterObject is used.
I have been tasked with converting this to asp.net core 2.0. however I am unable to find a way to either implement this or find an alternative to this in asp.net core 2.0.
the namespace Microsoft.AspNetCore.Hosting.Internal does not contain the registerobject method nor does it have the IRegisteredObject interface. I am at a loss on how to get this implemented.
The way to achieve similar goal in asp.net core is to use IApplicationLifetime interface. It has two properties two CancellationTokens,
ApplicationStopping:
The host is performing a graceful shutdown. Requests may still be
processing. Shutdown blocks until this event completes.
And ApplicationStopped:
The host is completing a graceful shutdown. All requests should be
completely processed. Shutdown blocks until this event completes.
This interface is by default registered in container, so you can just inject it wherever you need. Where you previously called RegisterObject, you instead call
// or ApplicationStopped
var token = lifeTime.ApplicationStopping.Register(OnApplicationStopping);
private void OnApplicationStopping() {
// will be executed on host shutting down
}
And your OnApplicationStopping callback will be invoked by runtime on host shutdown. Where you previously would call UnregisterObject, you just dispose token returned from CancellationToken.Register:
token.Dispose();
You can also pass these cancellation tokens to operations that expect cancellation tokens and which should not be accidentally interrupted by shutdown.

Start Background Task using ASP.Net Core Middleware

I'm attempting to run an asynchronous task when loading a page in ASP.Net Core, i.e., I want the task to run as soon as the user routes to the page but for the page to be displayed before the task has completed. It seems that with ASP.Net core you use middleware to perform such tasks. So I attempted to add the following to Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
// Other configurations here
app.Use(async (context, next) =>
{
if (context.Request.Path.Value.Contains("PageWithAsyncTask"))
{
var serviceWithAsyncTask = serviceProvider.GetService<IMyService>();
await serviceWithAsyncTask .DoAsync();
}
await next.Invoke();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
The problem with the above is that there is a delay in the page loading until DoAsync has complete since we don't call next.Invoke() until DoAsync is complete. How do I correctly implement the above such that next.Invoke() is called immediately after I've got DoAsync running?
In ASP.NET Core 2 the IHostedService is designed to run your background tasks.
Register the IHostedService as Singleton and it is automatically started at startup:
implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x
asp-net-core-background-processing
Since Asp.Net core 2.1 to use background tasks it is very convenient to implement IHostedService by deriving from the BackgroundService base class. Here is the sample taken from here:
public class MyServiceA : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine("MyServiceA is starting.");
stoppingToken.Register(() => Console.WriteLine("MyServiceA is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("MyServiceA is doing background work.");
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
Console.WriteLine("MyServiceA background task is stopping.");
}
}
Then just register it in Startup.ConfigureServices:
services.AddSingleton<IHostedService, MyServiceA>();
And as Stephen Cleary noted Asp.Net application may not be the best place for background tasks (e.g. when app is hosted in IIS it can be shut down because of app pool recycles), but for some scenarios it can be applied very well.
ASP.NET was not designed for background tasks. I strongly recommend using a proper architecture, such as Azure Functions / WebJobs / Worker Roles / Win32 services / etc, with a reliable queue (Azure queues / MSMQ / etc) for the ASP.NET app to talk to its service.
However, if you really want to - and are willing to accept the risks (specifically, that your work may be aborted), then you can use IApplicationLifetime.
Instead of
await serviceWithAsyncTask .DoAsync();
you could use
ThreadPool.QueueUserWorkItem(delegate {
SomeMethod();
});
In this approach an additional thread will be used from the thread pool which is of course a requirement if you want the code to run on a thread other than the main thread :-)
Any code placed after this block will run immediately. Also note that if your web server process (kestral) is recycled by IIS or whatever reverse proxy you are using then your background worker will be aborted immediately. So your background worker needs to be written defensively with this in mind.
Also please note that SomeMethod() is not itself an async method. But it's being called from a background thread so it's running asyncronously (i.e. independent of the main thread.)
Have a look at HangFire for managing background processing, works great in .Net Core: https://www.hangfire.io/

Notification of when continuous Azure WebJob is stopping for NoAutomaticTrigger type jobs

All,
I am migrating existing Worker Role code to an Azure Web job. I am trying to use the WebJob SDK (1.0) so that I have the full integration with the Azure Web Site.
My difficultly is that the JobHost doesn't play nicely with jobs that are outside it's usual Attribute based invoke options (Queues, Blobs etc.)
I already have standard code that I cannot change to listen to Azure Queues/Topics etc. so I cannot use the WebJob code to do this.
Therefore I need to use the WebJob Call method:
var cancelTokenSource = new CancellationTokenSource();
var onStartMethod = typeof(Program).GetMethod("OnStart", BindingFlags.Static | BindingFlags.Public);
host.CallAsync(onStartMethod, cancelTokenSource.Token)
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
NB: I am using my own CallAsync as all the advice is to use ConfigureAwait(false) when using libraries but the innards of JobHost doesn't do this, so I'm replicating it's "call" code myself but with the ConfigureAwait. The cancellation token doesn't do anything in JobHost as far as I can tell.
My problem is that I then need to call host.RunAndBlock(); to stop the job exiting, which is fine, but then I need to run some clean up processing. I can't make a new call to "CallAsync" with an OnStop method, as the Host is already being cancelled, so all I can do is make a direct call to my OnStop method. Unfortunately then I lose the ability to write to the WebSite log through the provided TextWriter class.
I think what I need is a way for JobHost to invoke my method within RunAndBlock, so I can then pick up the cancellation token fired when the host is shutting down, and then perform my cleanup code.... but there doesn't seem any way to do this.
Is there an obvious way I am missing? JobHost seems really poor at handling scenarios outside it's norm :(
As victor said, you could use Microsoft.Azure.WebJobs.WebJobsShutdownWatcher
This is an implementation of Amit solution : WebJobs Graceful Shutdown
So I've found a solution doing this :
No modification in the Program.cs
class Program
{
static void Main()
{
var host = new JobHost();
host.Call(typeof(Startup).GetMethod("Start"));
host.RunAndBlock();
}
}
the graceful shutdown goes in the Startup.cs :
public class Startup
{
[NoAutomaticTrigger]
public static void Start(TextWriter log)
{
var token = new Microsoft.Azure.WebJobs.WebJobsShutdownWatcher().Token;
//Shut down gracefully
while (!token.IsCancellationRequested)
{
// Do somethings
}
}
}
After the while loop, you could also stop started tasks.
NB: I am using my own CallAsync as all the advice is to use ConfigureAwait(false) when using libraries but the innards of JobHost doesn't do this, so I'm replicating it's "call" code myself but with the ConfigureAwait. The cancellation token doesn't do anything in JobHost as far as I can tell.
That's expected because you are passing your own cancellation token that is not cancelled by anyone. The webjobs cancellation token is cancelled when the shutdown notification is sent or the host is stopped/disposed. If you want to get a reference to the cancellation token from outside a webjob function, you have to keep it in a static variable or something similar.
If you want to use your own cancellation token you can use Microsoft.Azure.WebJobs.WebJobsShutdownWatcher to get the shutdown notification.
My problem is that I then need to call host.RunAndBlock(); to stop the job exiting, which is fine, but then I need to run some clean up processing. I can't make a new call to "CallAsync" with an OnStop method, as the Host is already being cancelled, so all I can do is make a direct call to my OnStop method. Unfortunately then I lose the ability to write to the WebSite log through the provided TextWriter class.
There is no out-of-the-box solution for this but you could call the cleanup function from the running webjob (if any). If you need cleanup outside of the function and you also want logging then you can only Console logging - write to console. The logs will be displayed on the WebJobs dashboard, on the webJob page. I'm curios, if you need cleanup outside of a function, what is the scenario?

HttpApplication does not quit

I have a single page app with Angular.js front, web api2 back end, also using Castle Windsor and SignalR.
I am using a c# component on the server that maintains server state. So, on Application_Start() I register the main component with Castle Windsor as Singleton.
IoC.Container.Register(Component.For(typeof(MainManager)).ImplementedBy(typeof(MainManager)).LifeStyle.Singleton);
(however, I tested PerWebRequest and few other lifestyles, but the main problem remains the same, the started task does not quit)
Then in my Web Api, I can execute commands against that instance.
[HttpGet]
public void StartProcess(Params p) {
IoC.Resolve<MainManager>().StartOperation(p);
}
and this also gives me opportunity to stop it from the website by calling another controller method
[HttpGet]
public void Stop() {
IoC.Resolve<MainManager>().RequestStop();
}
This works great for the most part. However, sometimes my application gets in a bad state (for a multitude of reasons, It can get restarted in prod) I can emulate this problem by modifying web.config during running the operation, so a lot of things reset (such as Signal-R connection), but the main operation does not stop running.
(In fact, once my application is in bad state I can no longer call that Stop controller method because MainManager has been reset, so the only way to stop it as of now is to reset the whole IIS. This is certainly not desired)
I am trying to figure out how to detect this state, and terminate the running process.
As one possible solution, I am experimenting with using Bound lifestyle (new in Castle Windsor 3), trying to scope my manager to my web api httpapplication, but no luck yet.
update
I tried making the main task method static
[HttpGet]
public void Start(ForceData data) {
MainManager.Start(data);
}
I believe this should take out the singleton instance out of equation, but the code still runs un-interrupted after touching web.config
update
took the MainManager class out of equation. All my web api method does now is loop + sleep
[HttpGet]
public void Start(ForceData data) {
foreach (var e in data.Members)
{
_log.Info("processing member: {0}", e.Email);
Thread.Sleep(1000);
}
}
this loop is also not interrupted after touching web.config.
So, at this point I am reading about MVC request lifecycle to figure out at which point this request goes zombie rouge
This is by design, as HttpApplication instances are not freed immediately when application restarts,
http://msdn.microsoft.com/en-us/library/vstudio/ms178473%28v=vs.100%29.aspx
When an application restart is required, ASP.NET will serve all pending requests from the existing application domain and the old assemblies before restarting the application domain and loading the new assemblies.
In all your sample Web API method, you can see the thread is still busy, which means ASP.NET runtime considers this request is still being processed.

Asynchronously consume synchronous WCF service

I’m currently in the process of migrating a client application over to .NET 4.5 to make use of async/await. The application is a client for a WCF service which currently offers only synchronous services. I am wondering now, how should I asynchronously consume this synchronous service?
I am using channel factories to connect to the WCF service, utilizing a service contract that is shared between both server and client. As such, I cannot use the auto-generation from VisualStudio or svcutil to generate asynchronous client proxies.
I have read this related question which is about whether to wrap the synchronous call on the client-side using Task.Run, or whether to extend the service contract with async methods instead. The answer suggests that having “real” asynchronous methods offered by the server is better for the client performance as no thread will have to actively wait for the service call to finish. This does make a lot of sense to me, and it would mean that the synchronous calls should be wrapped on the server-side.
On the other hand, Stephen Toub discorages doing this in general in this blog post. Now, he does not mention WCF there, so I am not sure if this just applies to libraries that run on the same machine, or if it also applies to things that run remotely, but where the introduction of asynchronicity has an actual impact on the connection/transfer.
And after all, as the server does not actually work asynchronously anyway (and likely won’t for another while), some threads will always have to wait: Either on the client or on the server. And that does also apply when consuming the services synchronously (currently, the client waits on a background thread to keep the UI responsive).
Example
To make the problem more clear, I have prepared an example. The full project is available for download here.
The server offers a synchronous service GetTest. This is the one that currently exists, and where the work happens—synchronously. One option would be to wrap this in an asynchronous method, for example using Task.Run, and offer that method as an additional service in the contract (requiring the contract interface to be expanded).
// currently available, synchronous service
public string GetTest() {
Thread.Sleep(2000);
return "foo";
}
// possible asynchronous wrapper around existing service
public Task<string> GetTestAsync() {
return Task.Run<string>(() => this.GetTest());
}
// ideal asynchronous service; not applicable as work is done synchronously
public async Task<string> GetTestRealAsync() {
await Task.Delay(2000);
return "foo";
}
Now, on the client-side, this service is created using a channel factory. That means I only have access to the methods as defined by the service contract, and I especially don’t have access to asynchronous service methods unless I explicitely define and implement them.
Depending on which methods are now available, I have two options:
I can asynchronously call the synchronous service by wrapping the call:
await Task.Run<string>(() => svc.GetTest());
I can asynchronously call the asynchronous service directly, which is provided by the server:
await svc.GetTestAsync();
Both works fine, and will not block the client. Both methods involve busy waiting on some end: Option 1 waits on the client, which is equivalent to what has been done before in a background thread. Option 2 waits on the server by wrapping the synchronous method there.
What would be the recommended way to make a synchronous WCF service async-aware? Where should I perform the wrapping, on the client or on the server? Or are there better options to do this without having to wait anywhere, i.e. by introducing “real” asynchronicity on the connection—like the generated proxies do?
The client side and server side are totally separate from an async standpoint, they do not care about each other at all. You should have your sync function on your sever and only the sync function on your server.
If you want to do it "right", on the client you will not be able to reuse the same interface for your generating your channel factory as the interface that is used to generate the server.
So your server side would look like this
using System.ServiceModel;
using System.Threading;
namespace WcfService
{
[ServiceContract]
public interface IService
{
[OperationContract]
string GetTest();
}
public class Service1 : IService
{
public string GetTest()
{
Thread.Sleep(2000);
return "foo";
}
}
}
and your client side would look like this
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SandboxForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var button = new Button();
this.Controls.Add(button);
button.Click += button_Click;
}
private async void button_Click(object sender, EventArgs e)
{
var factory = new ChannelFactory<IService>("SandboxForm.IService"); //Configured in app.config
IService proxy = factory.CreateChannel();
string result = await proxy.GetTestAsync();
MessageBox.Show(result);
}
}
[ServiceContract]
public interface IService
{
[OperationContract(Action = "http://tempuri.org/IService/GetTest", ReplyAction = "http://tempuri.org/IService/GetTestResponse")]
Task<string> GetTestAsync();
}
}
If your server-side API can be naturally async (like your Task.Delay example, rather than the Task.Run wrapper), declare it as Task-based in the contract interface. Otherwise, just leave it synchronous (but don't use Task.Run). Do not create multiple endpoints for the sync and async versions of the same method.
The generated WSDL remains the same for async and sync contract APIs, I just found out that myself: Different forms of the WCF service contract interface. Your clients will keep running unchanged. By making your server-side WCF method asynchronous, all you do is improve the service scalability. Which is a great thing to do, of course, but wrapping a synchronous method with Task.Run would rather hurt the scalability than improve it.
Now, the client of your WCF service doesn't know if the method is implemented as synchronous or asynchronous on the server, and it doesn't need to know that. The client can call your method synchronously (and block the client's thread) or it can call it asynchronously (without blocking the client's thread). In either case, it won't change the fact that the SOAP response message will be sent to the client only when the method has fully completed on the server.
In your test project, you're trying to exposes different versions of the same API under different contract names:
[ServiceContract]
public interface IExampleService
{
[OperationContract(Name = "GetTest")]
string GetTest();
[OperationContract(Name = "GetTestAsync")]
Task<string> GetTestAsync();
[OperationContract(Name = "GetTestRealAsync")]
Task<string> GetTestRealAsync();
}
This doesn't really make sense, unless you want to give your client an option to control if the method runs synchronously or asynchronously on the server. I cannot see why you would want this, but even if you have your reason, you'd be better off controlling this via a method argument and a single version of the API:
[ServiceContract]
public interface IExampleService
{
[OperationContract]
Task<string> GetTestAsync(bool runSynchronously);
}
Then, in the implementation your could do:
Task<string> GetTestAsync(bool runSynchronously)
{
if (runSynchronously)
return GetTest(); // or return GetTestAsyncImpl().Result;
else
return await GetTestAsyncImpl();
}
#usr explains this in great details here. To sum up, it is not like the WCF service calls back your client to notify about the completion of the async operation. Rather, it simply sends back the full SOAP response using the underlying network protocol when it's done. If you need more than that, you could use WCF callbacks for any server-to-client notifications, but that would span the boundaries of a single SOAP message.
This isn't horrible: https://stackoverflow.com/a/23148549/177333. You just wrap your return values with Task.FromResult(). You have to change the service side, but it's still synchronous and you're not using an extra thread. That changes your server-side interface which can still be shared with the client so it can wait asynchronously. Otherwise it looks like you have to maintain separate contracts on server and client somehow.

Categories