2
\$\begingroup\$

I'm trying to make a timed background service in .NET Core (I found this approach in Microsoft Docs), that every 15 seconds it gets data from the database (1000 rows max, if something exists) then sends it to the API using a foreach loop. If a response status code is not 200 or 202, I change thr status column by id in the database.

How can I make this code faster? Should I use another approach?

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FDProcessor
{
    class FDSenderService : IHostedService, IDisposable
    {
        private Timer timer;
        private HttpClient httpClient = new HttpClient
        {
            BaseAddress = new Uri("https://example.com")
        };

        public Task StartAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("Service is started.");
            timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(15));
            return Task.CompletedTask;
        }

        private async void DoWork(object state)
        {
            var data = DbManager.GetTransactions();

            foreach (var r in data)
            {
                StringContent jsonRequestBody = new StringContent(JsonConvert.SerializeObject(r));
                var response = await httpClient.PostAsync("/example/path", jsonRequestBody);

                if (!response.IsSuccessStatusCode)
                {
                    Console.WriteLine("Bad request. Status returned.");
                    Console.WriteLine(await response.Content.ReadAsStringAsync());
                    DbManager.UpdateTransaction(null, r.TrnID);
                }
            }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("Stopping!");
            timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }

        public void Dispose()
        {
            timer.Dispose();
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Is DoWork considered Atomic? e.g. when calling StopAsync, does the current execution of DoWork need to finish? \$\endgroup\$ – dfhwze Jun 11 at 5:54
3
\$\begingroup\$

If Dowork takes longer than 15 seconds to execute, it will be called a second time. Will this cause issues? One way around that would be to disable the timer while you're doing work, then start it up again when the work is done, or add an appropriately typed and thread safe "busy" member to the class so that you can skip starting any new work if work is currently being done.

\$\endgroup\$
  • \$\begingroup\$ Sorry, I just realized that I didn't mentioned it before. But every 15 seconds DbManager will get new set of data(next 1000 rows). So it doesn't matter if DoWork finished job or not. I think, that multiple threads can work in the same time and that's exactly what I need. \$\endgroup\$ – Alexander Ts Jun 11 at 9:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.