Reputation: 375
I'm trying to make call to a function every specified interval of time, for that m using Background service, here is what I have done: Here is the Alerting controller where I have the function:
public class AlertingController : ControllerBase
{
private readonly DatabaseContext _context;
private readonly IMapper _mapper;
public AlertingController(DatabaseContext context, IMapper mapper)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
public AlertingController()
{
}
//function that adds in the DB
public async Task<AlertingResponse> GetAlertingToDB()
{
AlertingResponse dataGet;
using (var httpClient = new HttpClient())
{
using (var response = await httpClient
.GetAsync(MetricApiLink))
{
string apiResponse = await response.Content.ReadAsStringAsync();
dataGet = JsonConvert.DeserializeObject<AlertingResponse>(apiResponse);
}
}
if (dataGet.data.alerts != null || dataGet.data.alerts.Count > 0)
{
foreach (var alert in dataGet.data.alerts)
{
CreateAlertQuery QueryAlert = new CreateAlertQuery();
QueryAlert.Name = alert.labels.alertname;
QueryAlert.Instance = alert.labels.instance;
QueryAlert.Serverity = alert.labels.severity;
QueryAlert.Summary = alert.annotations.summary;
QueryAlert.State = alert.state;
QueryAlert.ActiveAt = alert.activeAt;
var _Alert = _mapper.Map<AlertingDataModel>(QueryAlert);
_context.Alertings.Add(_Alert);
await _context.SaveChangesAsync();
}
}
return null;
}
}
I have tested the method with a HTTPGET request, it works fine, add the alerts into my database:
I have created a scooped service where I called the function GetAlertingToDB()
:
internal interface IScopedAlertingService
{
Task DoWork(CancellationToken stoppingToken);
}
public class ScopedAlertingService : IScopedAlertingService
{
private int executionCount = 0;
private readonly ILogger _logger;
public ScopedAlertingService(ILogger<ScopedAlertingService> logger)
{
_logger = logger;
}
public async Task DoWork(CancellationToken stoppingToken)
{
AlertingController _AlertingToDB = new AlertingController();
while (!stoppingToken.IsCancellationRequested)
{
executionCount++;
_logger.LogInformation(
"Scoped Processing Service is working. Count: {Count}", executionCount);
await _AlertingToDB.GetAlertingToDB();
await Task.Delay(10000, stoppingToken);
}
}
}
I have also created the Class that will consume my service, and will run in the BackGround:
public class ConsumeScopedServiceHostedService : BackgroundService
{
private readonly ILogger<ConsumeScopedServiceHostedService> _logger;
public ConsumeScopedServiceHostedService(IServiceProvider services,
ILogger<ConsumeScopedServiceHostedService> logger)
{
Services = services;
_logger = logger;
}
public IServiceProvider Services { get; }
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service running.");
await DoWork(stoppingToken);
}
private async Task DoWork(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service is working.");
using (var scope = Services.CreateScope())
{
var scopedProcessingService =
scope.ServiceProvider
.GetRequiredService<IScopedAlertingService>();
await scopedProcessingService.DoWork(stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service is stopping.");
await Task.CompletedTask;
}
}
I injected the dependencies on the Startup Class and added the hosted service:
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedAlertingService, ScopedAlertingService>();
The functions are working just fine untill a call the GetAlertingToDB()
function and it doesn't work.
Any help would be great, thanks everyone :)
Upvotes: 5
Views: 14113
Reputation: 11153
Personally I would rearrange your solution so that your background service doesn't need to create a Controller
. Instead the controller, if you still need it at all, should call into your ScopedAlertingService
where the work is performed once. Your background service can simply loop forever, with an await Task.Delay()
.
public class ScopedAlertingService : IScopedAlertingService
{
public async Task DoWork(CancellationToken stoppingToken)
{
// move contents of your AlertingController.GetAlertingToDB here
}
}
public class ConsumeScopedServiceHostedService : BackgroundService
{
private readonly IServiceProvider _services;
public ConsumeScopedServiceHostedService(IServiceProvider services)
{
_services = services;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(10000, stoppingToken);
using (var scope = _services.CreateScope())
{
var scopedProcessingService =
scope.ServiceProvider
.GetRequiredService<IScopedAlertingService>();
await scopedProcessingService.DoWork(stoppingToken);
}
}
}
}
Upvotes: 3
Reputation: 4376
There are several options for doing this.
Please read the following link from the Microsoft Documentation which has several examples on how to do this in .NET Core and ASP.NET Core:
It is called Worker Services.
You basically implement two interfaces: IHostedService, IDisposable
Then you register your service inside you Startup class in your ConfigureServices method like this:
services.AddHostedService<MyCoolWorkerServiceClass>();
For a Complete Example
One last sugestion. The example uses System.Threading.Timer... But I think it is better to use a System.Timers.Timer with AutoReset = false.
The reason is to avoid overlapping runs of your service. Once a run is done then you start your timer again.
But then again it all depends on what you want to achieve.
Upvotes: 0
Reputation: 31
Hangfire RecurringJob would be an option for you case. you can check it here https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html. The benefit of using it is: you have a dashboard to check when the task will be fired and the result of the task.
Upvotes: 2