在Windows服务的线程内定时器

本文关键字:定时器 线程 Windows 服务 | 更新日期: 2023-09-27 18:16:49

我想不出解决这个问题的最佳方法。

现在我有一个windows服务,它唯一的任务是从一个特定的DSN数据库收集数据,然后发送电子邮件,如果数据是有效的。该服务包含一个计时器,每5分钟滴答一次,并执行上述任务。

现在我需要重写windows服务,以便能够在1个以上的DSN上运行。我正在考虑在windows服务中创建几个线程,然后在每个线程中再设置一个单独的计时器。这是个好主意吗?怎么做?我想避免每个DSN都有一个windows服务。

如果没有意义,我试着画一下

                             Windows Service

Thread1 (DSN1 )----------------------------- Thread2 (DSN2 )---------------------- Thread3 (DSN3)
每X分钟计时器(蜱虫 )----------------- 计时器(相同 )------------------------- 计时器(同样)
逻辑 ()--------------------------------------------- 逻辑 --------------------------------- 逻辑()

希望我的问题有意义

在Windows服务的线程内定时器

据我所知,每个计时器都代表一个线程。知道了这一点,我将尝试为每个给定的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();
    }
}

每个dsn需要在单独的线程上吗?

如果要将Email检索和验证逻辑封装在线程调用的某种服务中,那么可以对调度线程隐藏多个dsn的事实。例如,IEmailService可能具有以下契约:

public interface IEmailService
{
    void SendEmailsToValidAddresses();
}

的实现可能是这样的:

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
        ...
    }
}        

通过这种方式,你的计时器逻辑可以保持不变,在一个线程上,而发送电子邮件的关注被分离到IEmailService中。这也意味着你可以实现一个SingleSourceEmailService和一个MultipleSourceEmailService,并在代码完成时交换多个源,而服务的消费者永远不会知道。

当然,上面实现的EmailService将顺序地从多个源发送邮件——如果你需要它并行运行,你可以改变EmailService,为你拥有的每个dsn启动一个新的线程,你甚至可以称之为:MultiThreadedMultipleSourceEmailService,但作为IEmailService的消费者,你的调度永远不会知道区别。

使用后台worker。http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

只需为每个DSN启动一个,非常流畅且易于使用。

尝试使用System.Threading.Timer

这里是我的项目的示例代码,希望这有助于

public void StartDSNTimers()
    {
        _tmr1 = new Timer(CheckMessages, dsn1, 0, 60000);
        _tmr2 = new Timer(CheckMessages, dsn2, 0, 60000);
        _tmr3 = new Timer(CheckMessages, dsn3, 0, 60000);
    }
    private void CheckMessages(object obj)
    {
        //Logic
    }