I'm trying to use Abp.Quartz for scheduling jobs.
Working with net core 2.2, abp 4.5
I did everything like in docs here
https://aspnetboilerplate.com/Pages/Documents/Quartz-Integration , only resolved it in PostInitialize method.
At the end I tried exactly the same as in docs (start scheduler from controller).
But it not worked too. Job is not starting.
namespace Cloud
{
[DependsOn(typeof(AbpZeroCoreModule),
typeof(AbpQuartzModule))]
public class CloudCoreModule : AbpModule
{
public override void PreInitialize()
{
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(CloudCoreModule)
.GetAssembly());
}
public override void PostInitialize()
{
IocManager.Resolve<IQuartzScheduleJobManager>().ScheduleAsync<ApiRequestQueues.ApiRequestProcessor>(
job =>
{
job
.WithIdentity("RevolutApiProcessor")
.WithDescription("A job witch processing request front");
},
trigger =>
{
trigger
.StartNow()
.WithSimpleSchedule(
schedule =>
{
schedule
.RepeatForever()
.WithIntervalInSeconds(5)
.Build();
});
});
}
}
}
and here is class ApiRequestProcessor
public class ApiRequestProcessor : JobBase, ITransientDependency
{
public override async Task Execute(IJobExecutionContext context)
{
//some work
}
}
Better late to the party than never.
I've managed to get this working, though without Abp.Quartz package. If you're able to use the standard Quartz package, you can use the following steps:
Define and set up your jobs as normal in Startup.cs
Ensure that your class implements both IJob for Quartz to be happy, and ITransientDependency for ASP.NET Boilerplate to be happy
Very important, if your job code uses DbContext in any way, you need to ensure that the [UnitOfWork] decorator is on your job class (which is anyway important to ensure your jobs run atomically and do not affect any other transactions which may be occurring on your server)
In short, a working bare-bones job class might look like this:
using System;
using Quartz;
namespace MyProject.MyJobService
{
[UnitOfWork]
public class SimpleJob : IJob, ITransientDependency
{
public async Task Execute(IJobExecutionContext context)
{
Console.WriteLine("Hello from quartz job!");
}
}
}
More information and discussion can be found here (also how I finally arrived at this solution): https://github.com/aspnetboilerplate/aspnetboilerplate/issues/3757
When in doubt, carefully read what Quartz is telling you in the application output - it usually gives clues as to what is wrong, but I'm confident my solution will work for you 😊
Related
Is it possible to detect if code is running as a hangfire job in C#?
Thank you
I would expect that some global system variable exists and indicates code is running as a part of hangfire job.
I would expect that some global system variable exists and indicates
code is running as a part of hangfire job.
I would be curious about your usecase. Having code depending explicitly on the execution context is more difficult to maintain and test in my opinion.
Is it because your code depends on HttpContext, which is not available when running the task with Hangfire ?
Anyway, you could achieve what you want with AsyncLocal and Hangfire ServerFilters
public static class HangfireTaskMonitor
{
public static AsyncLocal<bool> IsRunningInBackground { get; } = new AsyncLocal<bool>();
}
public class ContextTrackedAttribute : JobFilterAttribute, IServerFilter
{
public void OnPerforming(PerformingContext filterContext)
{
HangfireTaskMonitor.IsRunningInBackground.Value = true;
}
public void OnPerformed(PerformedContext filterContext)
{
HangfireTaskMonitor.IsRunningInBackground.Value = false;
}
}
Then put the [ContextTracked] attribute on your job method and test HangfireTaskMonitor.IsRunningInBackground.Value whenever you want.
The idea is somewhat simplified for clarity. For a more decoupled solution, I would have the HangfireTaskMonitor being injected as a singleton instead of a static class ; have the filter be a simple filter declared upon Hangfire configuration, instead of being an attribute.
How can I schedule a task with Umbraco Cms. I would like to create scheduled emails with Umbraco 9.
I have tried unsuccessfully to get a documentation that could help. Could you please help or refer me to a documentation
Just write an API-Controller, which does the work. Then use the windows task scheduler or a cron job on linux to call the url of the API.
public class EmailsController : UmbracoApiController
{
[HttpGet]
public string Create()
{
// Do whatever you need
return "OK";
}
}
Then call the url https://yoursite.com/umbraco/api/emails/create
Firstly, have a read about hosted services, which are a feature provided by the .NET 5 framework, and which Umbraco are using themselves.
In Umbraco v9, you can implement your own version by inheriting from RecurringHostedServiceBase
The documentation is lacking on this, but have a look at the Umbraco implementation to see some examples - https://github.com/umbraco/Umbraco-CMS/tree/v9/dev/src/Umbraco.Infrastructure/HostedServices
This is also a useful post that provides some further details - https://our.umbraco.com/forum/umbraco-9/106304-creating-scheduled-tasks-in-umbraco-9
An example:
public class YourScheduledTask : RecurringHostedServiceBase
{
private readonly ILogger<YourScheduledTask> _logger;
public YourScheduledTask(ILogger<YourScheduledTask> logger)
: base(TimeSpan.FromMinutes(2),
TimeSpan.FromMinutes(2))
{
_logger = logger;
}
public override async Task PerformExecuteAsync(object state)
{
try
{
// your logic here
}
catch (Exception e)
{
_logger.LogError("exception when persisting collections: {exception}", e.ToString());
}
}
}
Don't forgot to resgister this in the IOC:
public class IoCComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.Services.AddHostedService<YourScheduledTask>();
}
}
I am working on Azure WebJobs (3.0.6) using dotnet core. I referred Microsoft's Get Started Guide. Per the example I wanted to have a console logging to begin with. The scope of that guide is limited. In my application, I will be using many classes in a different dll. I am not able to figure out how can I add logging in those classes. The sample code is
// The main method
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
});
builder.ConfigureLogging((context, b) =>
{
b.AddConsole();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
// The queue trigger class
public class QueueListenerService
{
public static void QueueListener([QueueTrigger("myqueue")] string message, ILogger logger)
{
logger.LogInformation("The logger works here");
// how can I pass an instance of ILogger in the constructor below
MyWorker myWorker = new MyWorker();
}
}
// MyWorker Class in a different assembly
public class MyWorker
{
public MyWorker(ILogger logger)
{
// I want to use logger here being injected
}
}
I have referred several examples of DI in dotnet core console applications and they use service collection approach. I also check this blog but to me, this is what I have done and yet my ILogger is not being resolved. It ask me to pass an instance of ILogger when I create MyWorker instance
You are close to the solution. The main thing you need to change is to let the service collection create the MyWorker instance for you.
I quickly extended my recent Webjob sample project to include console logging with dependency injection. See this commit for how I added it.
You mainly need to use constructor dependency injection for your QueueListenerService.
builder.ConfigureServices(services =>
{
services.AddScoped<QueueListenerService>();
services.AddScoped<MyWorker>();
});
public class QueueListenerService
{
public QueueListenerService(MyWorker worker){
_Worker = worker;
}
public static void QueueListener([QueueTrigger("myqueue")] string message, ILogger logger)
{
logger.LogInformation("The logger works here");
_Worker.DoStuff()
}
}
I have a handful of existing Owin middleware classes, originally written for .Net 4.6 apps, that follow this pattern:
public class MyMiddleware : OwinMiddleware
{
public MyMiddleware(OwinMiddleware next) : base(next)
{ }
public override async Task Invoke(IOwinContext context)
{
// do stuff
await Next.Invoke(context)
}
}
I'm writing a new .Net Core 2.0 app that I'd like to use those middlewares in (as well as some "new style" middlewares that aren't based on Owin). I'm having trouble finding good documentation or examples of doing this, at least ones that are similar to what I have (for example, this)
The one promising thing I have found is that the Microsoft.AspNetCore.Owin package includes an extension method, UseOwin() that seems to be the path forward, but I'm unable to decipher how to use it to invoke my "legacy" middlewares above. I realize that I should use UseOwin() when configuring my IApplicationBuilder but I'm not smart enough to get the details from what I'm reading online.
What's the most straightforward way to do this?
It seems that the most straightforward way to do this is through the UseOwin extension method.
I was able to get this to work:
public class MyTestMiddleware : OwinMiddleware
{
public MyTestMiddleware(OwinMiddleware next) : base(next) {}
public override async Task Invoke(IOwinContext context)
{
System.Diagnostics.Debug.WriteLine("INVOKED");
await Next.Invoke(context);
}
}
app.UseOwin(setup => setup(next =>
{
var owinAppBuilder = new AppBuilder();
// set the DefaultApp to be next so that the ASP.NET Core pipeline runs
owinAppBuilder.Properties["builder.DefaultApp"] = next;
// add your middlewares here as Types
owinAppBuilder.Use(typeof(MyTestMiddleware));
return owinAppBuilder.Build<Func<IDictionary<string, object>, Task>>();
}));
Notice that Microsoft seems to have pushed hard against OwinMiddleware classes, as this feels very hacky.
I just discovered IHostedService and .NET Core 2.1 BackgroundService class. I think idea is awesome. Documentation.
All examples I found are used for long running tasks (until application die).
But I need it for short time. Which is the correct way of doing it?
For example:
I want to execute a few queries (they will take approx. 10 seconds) after application starts. And only if in development mode. I do not want to delay application startup so IHostedService seems good approach. I can not use Task.Factory.StartNew, because I need dependency injection.
Currently I am doing like this:
public class UpdateTranslatesBackgroundService: BackgroundService
{
private readonly MyService _service;
public UpdateTranslatesBackgroundService(MyService service)
{
//MService injects DbContext, IConfiguration, IMemoryCache, ...
this._service = service;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await ...
}
}
startup:
public static IServiceProvider Build(IServiceCollection services, ...)
{
//.....
if (hostingEnvironment.IsDevelopment())
services.AddSingleton<IHostedService, UpdateTranslatesBackgroundService>();
//.....
}
But this seems overkill. Is it? Register singleton (that means class exists while application lives). I don't need this. Just create class, run method, dispose class. All in background task.
There's no need to do any magic for this to work.
Simply:
Register the service you need to run in ConfigureServices
Resolve the instance you need in Configure and run it.
To avoid blocking, use Task.Run.
You must register the instance, or dependency injection won't work. That's unavoidable; if you need DI, then you have to do it.
Beyond that, it's trivial to do what you ask, like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient<MyTasks>(); // <--- This
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Blocking
app.ApplicationServices.GetRequiredService<MyTasks>().Execute();
// Non-blocking
Task.Run(() => { app.ApplicationServices.GetRequiredService<MyTasks>().Execute(); });
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
public class MyTasks
{
private readonly ILogger _logger;
public MyTasks(ILogger<MyTasks> logger)
{
_logger = logger;
}
public void Execute()
{
_logger.LogInformation("Hello World");
}
}
BackgroundService exists specifically for long running processes; if it's a once of, don't use it.
Well I think there is more then one question here.
First let me point out something you are probably aware of async != multithreaded.
So BackgroundService will not make you app "multithreaded" it can run inside a single thread without no problem. And if you are doing blocking operations on that thread it will still block startup. Lets say in the class you implement all the sql queries in a not real async way something similar to
public class StopStartupService : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
System.Threading.Thread.Sleep(1000);
return Task.CompletedTask;
}
}
This will still block startup.
So there is another question.
How should you run background jobs?
For this in simple cases Task.Run(Try to avoid Task.Factory.StartNew if you are not sure how to configure it) should do the job, but that is not to say this is the best or a good way to do it. There are a bunch of open source libraries that will do this for you and it might be good to have a look at what they provide. There are a lot of problems you might not be aware of , that can create frustrating bugs if you just use Task.Run
The second question I can see is.
Should I do fire and forget in c#?
For me this is a definite NO(but XAML people might not agree). No matter what you do, you need to keep track of when the thing you are doing is done. In your case you might want to do a rollback in the database if someone stops the app before the queries are done. But more than that you would want to know when you can start using the data that the queries provided. So BackgroundService helps you to simplify the execution but is difficult to keep track of completion.
Should you use a singleton?
As you already mentioned using singletons can be a dangerous thing especially if you don't clean things properly, but more than that the context of the service you are using will be the same for the life time of the object. So with this all depends on your implementation of the service if there will be problems.
I do something like this to do what you want.
public interface IStartupJob
{
Task ExecuteAsync(CancellationToken stoppingToken);
}
public class DBJob : IStartupJob
{
public Task ExecuteAsync(CancellationToken stoppingToken)
{
return Task.Run(() => System.Threading.Thread.Sleep(10000));
}
}
public class StartupJobService<TJob> : IHostedService, IDisposable where TJob: class,IStartupJob
{
//This ensures a single start of the task this is important on a singletone
private readonly Lazy<Task> _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
public StartupJobService(Func<TJob> factory)
{
//In order for the transient item to be in memory as long as it is needed not to be in memory for the lifetime of the singleton I use a simple factory
_executingTask = new Lazy<Task>(() => factory().ExecuteAsync(_stoppingCts.Token));
}
//You can use this to tell if the job is done
public virtual Task Done => _executingTask.IsValueCreated ? _executingTask.Value : throw new Exception("BackgroundService not started");
public virtual Task StartAsync(CancellationToken cancellationToken)
{
if (_executingTask.Value.IsCompleted)
{
return _executingTask.Value;
}
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
if (_executingTask == null)
{
return;
}
try
{
_stoppingCts.Cancel();
}
finally
{
await Task.WhenAny(_executingTask.Value, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
public static void AddService(IServiceCollection services)
{
//Helper to register the job
services.AddTransient<TJob, TJob>();
services.AddSingleton<Func<TJob>>(cont =>
{
return () => cont.GetService<TJob>();
});
services.AddSingleton<IHostedService, StartupJobService<TJob>>();
}
}
There is a library called Communist.StartupTasks that handles this exact scenario. It's available on Nuget.
It's designed specifically to run tasks during application launch in a .NET Core App. It fully supports dependency injection.
Please note that it executes tasks sequentially and it blocks until all tasks are complete (i.e. your app won't accept requests until startup tasks complete).