简体   繁体   中英

how do i make a background worker to update a datastore every 5 minutes in asp.net core

I've followed the getting started tutorial and currently have a TODO CRUD app.

https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api-mac?view=aspnetcore-2.1

I want to add a background worker that updates the todo database every 5 minutes and sets Item 1 to a random value for its Name, and isCompleted properties.

This is pretty easy in Java SpringBoot or Elixir's Phoenix... Is there a quick and painless way in c# to do this?

The doc I found on Microsoft website was from 2012... so I assume there is a more elegant way to do this by now.

Edit: I went with DNTScheduler.Core and it was relatively painless to set up. Followed the exampleApp setup that was on github repo and here is the task i ended up using:

using System;
using System.Threading.Tasks;
using DNTScheduler.Core.Contracts;
using Microsoft.Extensions.Logging;
using myapp.Models;

namespace MyApp.Tasks
{
    public class TaskOne : IScheduledTask
    {
        private readonly ILogger<DoBackupTask> _logger;
        private readonly TodoContext _context; // autoinjects since it was added in startup.cs in configure()

        public TaskOne(ILogger<DoBackupTask> logger, TodoContext context)
        {
            _logger = logger;
            _context = context;
        }

        public Task RunAsync()
        {

            var todo = _context.TodoItems.Find(1);
            if (todo == null)
            {
                return Task.CompletedTask;
            }

            string[] names = new string[] { "val1", "val2"};
            Random r = new Random();
            string random_name = names[r.Next(0, names.Length)];
            todo.Name = random_name;

            _context.TodoItems.Update(todo);
            _context.SaveChanges();
            _logger.LogInformation("Ran My Task\n\n ");

            return Task.CompletedTask;

        }
    }
}

I would suggest you use Scheduler, there are some packages that can do that, but the best package that I have seen so far is DNTScheduler.Core

DNTScheduler.Core is a lightweight ASP.NET Core's background tasks runner and scheduler.

for more information, you can visit this link

I would argue that the correct answer is wrong if you want to follow the native practice.

Make use of IHostedService to perform repetitive actions.

Here's an answer I've written that addresses that.

There is a saying i've read somewhere: "If its worth doing, its worth doing right. If its not worth doing right - find something that is."

So, as other colleagues already said, web application is not meant to be a container for background processes for reasons already mentioned.

Depending on your environment, you'll be much better off using:

  1. windows services or even windows scheduler (on classic hosting) or some of the libraries for scheduling but outside of the web app. then, those scheduler, whichever it is, could just trigger API endpoint within your web app so you have business logic at one place
  2. azure scheduler if you work with azure

pretty much anything else is looking for trouble when you don't need one.

In this sample I Insert a record to my database ( Word-Suggestion-Table in here) every hour using UnitOfWork and Repository Pattern . No error on Cannot consume scoped service *IUnitOfWork* from singleton

1- Add work class and IWork interface as below:

using System.Threading;
using System.Threading.Tasks;

namespace Map118.App.BackgroundTasks
{
    public interface IWorker
    {
        Task DoWork(CancellationToken cancellationToken);
    }
}

Work.cs :

using Map118.DataLayer.IRepositories;
using Map118.Models;
using Microsoft.Extensions.DependencyInjection; 
using System; 
using System.Threading;
using System.Threading.Tasks;

namespace Map118.App.BackgroundTasks
{
    public class Worker : IWorker
    {            
        private readonly IServiceProvider serviceProvider;
        public Worker( IServiceProvider serviceProvider)
        {               
            this.serviceProvider = serviceProvider;
        }

        public async Task DoWork(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                using (var scope = serviceProvider.CreateScope())
                {
                    var _unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
                    while (!stoppingToken.IsCancellationRequested)
                    {
                        WordSuggestion wordSuggestion = new WordSuggestion()
                        {
                            word = Guid.NewGuid().ToString(),
                        };
                        await _unitOfWork.wordSuggestionRepository.Add(wordSuggestion);
                        await _unitOfWork.Save();
                        await Task.Delay(1000 * 3600);
                    }
                }
            }
        }
    }
}

2- Add another class as below:

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace Map118.App.BackgroundTasks
{
    public class UserActivitiesCleaner : BackgroundService
    {
        private readonly IWorker worker;

        public UserActivitiesCleaner(IWorker worker)
        {
            this.worker = worker;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await worker.DoWork(stoppingToken);            
        }
    }
}

3- Add services to Startup.cs :

services.AddHostedService<UserActivitiesCleaner>();
services.AddSingleton<IWorker, Worker>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM