Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timer within Thread within Windows Service

I cant figure out how to proceed the best way with this problem.

Right now I have a windows service which only task is to gather data from a database with a specific DSN and then send out an email if the data is valid. The service contains a timer which ticks every 5 minuts and performs the tasks above.

Now I need to re-write the windows service to be able to run on more than 1 DSN. I was thinking of making several threads inside the windows service and then again have a seperat timer inside each thread. Is this a good idea and how can this be done? I want to avoid having a windows service for each DSN.

Ill try to draw it if I dont make any sense

                             Windows Service

Thread1(DSN1)-----------------------------Thread2(DSN2)----------------------Thread3(DSN3)
Timer(ticks every X minuts)-----------------Timer(same)-------------------------Timer(same)
Logic()---------------------------------------------Logic---------------------------------Logic()

Hope my problem makes sense :)

like image 354
mRf Avatar asked Dec 22 '22 05:12

mRf


2 Answers

As far as I Know each timer represents a thread on its own. Knowing this, I would try to dynamically create timer objects for each given dsn.

public partial class Service1 : ServiceBase
{
    public Service1()
    {
        InitializeComponent();
    }

    private List<GetDataFromDSN> list = null;
    protected override void OnStart(string[] args)
    {
        list = new List<GetDataFromDSN>();
        // assume args contains your given dsn values
        foreach (string dsn in args)
        {
            GetDataFromDSN newObj = new GetDataFromDSN();
            newObj.DSN = dsn;
            list.Add(newObj);
            newObj.Start();
        }
    }
}

public class GetDataFromDSN
{
    public string DSN { get; set; }
    private Timer timer = null;
    private double interval = 1000*60*5; // 5 minutes interval
    public GetDataFromDSN()
    {
        // init your object
        timer = new Timer(interval);
        timer.Elapsed +=new ElapsedEventHandler(timer_Elapsed);
    }
    private void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // do what ever you want
    }
    public void Start() // or even make timer public
    {
        timer.Start();
    }
    public void Stop()
    {
        timer.Stop();
    }
}
like image 68
Pilgerstorfer Franz Avatar answered Jan 03 '23 14:01

Pilgerstorfer Franz


Do each of the DSNs need to be on a separate Thread?

If you were to encapsulate the Email retrieval and validation logic within some sort of service that the Thread invoked, the fact that there were multiple DSNs could be hidden from the scheduling thread. For instance, an IEmailService might have the following contract:

public interface IEmailService
{
    void SendEmailsToValidAddresses();
}

and the implementation might look something like this:

public class MultipleSourcesEmailService : IEmailService
{
    private IEnumerable<IDatabaseSource> databases;
    public EmailService(params IDatabaseSource[] sources)
    {
        databases = new List<IDatabaseSource>(sources);        
    }

    public void SendEmailsToValidAddresses()
    {
        foreach(var database in databases)
        {
            var emailAddresses = database.SelectAllEmailAddresses();
            ValidateAndSendEmailsTo(emailAddresses);
        }
    }

    public void ValidateAndSendEmailsTo(IEnumerable<string> emailAddresses)
    {
        // Perform appropriate logic
        ...
    }

}        

In this way, your timer logic can remain the same and on a single Thread whilst the concern of sending emails is separated into the IEmailService. This also means that you could implement a SingleSourceEmailService and a MultipleSourceEmailService and swap the multiple sources in when you're code complete and the consumer of the service need never know.

Of course, the EmailService as implemented above will SendEmails from multiple sources sequentially - if you need it to run in parallel you could change the EmailService to kick off a new Thread for each of the DSNs that you have, you could even call it the: MultiThreadedMultipleSourceEmailService but as a consumer of the IEmailService your scheduling will never know the difference.

like image 41
Tom Scott Avatar answered Jan 03 '23 15:01

Tom Scott