0

我有一种情况,我创建了一个长时间运行的任务列表,它监视一些系统/网络资源,然后发送电子邮件登录到 txt 文件,并在满足某些条件时调用 Web 服务。然后再次开始监控。这些任务是在 Windows 服务中创建的,因此将一直运行。

我希望他们引发事件或通知父类(创建它们),它将执行我上面提到的 3 个操作,而不是任务中的每个对象自己执行。

以及如何控制一次只有一个任务使用该父类的方法。由于涉及电子邮件和 Web 服务调用,因此两个并发请求可能会破坏代码。

更新

这些 Watcher 分为三种类型,每种都实现了以下接口。

public interface IWatcher
{
    void BeginWatch();        
}

实现的类是

//this watcher is responsible for watching over a sql query result
public class DBWatcher : IWatcher
{
    ....
    void BeginWatch()
    {
        //Here a timer is created which contiously checks the SQL query result.
        //And would Call SERVICE, send an EMAIL and LOG into a file

        Timer watchIterator = new Timer(this._intervalMinutes * 60000);
        watchIterator.Elapsed += new ElapsedEventHandler(_watchIterator_Elapsed);
        watchIterator.Start();
    }

    void _watchIterator_Elapsed(object sender, ElapsedEventArgs e)
    {
        //1. Check Query result
        //3. Call SERVICE, send an EMAIL and LOG into a file if result is not as was expected
        //I have done the work to this part!

        //And I can do the functions as follows .. it should be simple.
        //*********************
        //SendEmail();
        //LogIntoFile();
        //CallService();

        //But I want the above three methods to be present in one place so i dont have to replicate same functionality in different watcher.
        //One approach could be to create a seperate class and wrape the above mentioned functions in it, create an instance of that class here and call them.
        //Second option, which I am interested in but dont know how to do, is to have this functionality in the parent class which actually creates the tasks and have each watcher use it from HERE ...
    }
    ....
}


//this watcher is responsible for watching over Folder
public class FolderWatcher : IWatcher
{
    ....
    void BeginWatch()
    {
         ///Same as above
    }
    ....
}

首先,我从 XML 文件创建一个列表。这可以包含多个 DBWatcher 实例,它们将持续观察不同的查询结果,FolderWatcher 将持续观察不同的文件夹。

创建列表后,我调用以下函数来创建单独的任务。我多次调用这个函数来创建一组不同的观察者。

    private void _createWatcherThread(IWatcher wat, CancellationTokenSource cancellationToken)
    {
        //This represents a watcher that will watch some specific area for any activities
        IWatcher watcher = wat.Copy();
        bool hasWatchBegin = false;
        try
        {
            //run forever
            for (;;)
            {
                //dispose the watcher and stop this thread if CANCEL token has been issued
                if (cancellationToken.IsCancellationRequested)
                {
                    ((IDisposable)watcher).Dispose();
                    break;
                }
                else if (!hasWatchBegin)
                {
                    //This method of a watcher class creates a timer. which will
                    //continously check the status after a few minutes... So its the 
                    //timer's elapsed method in Watcher object which will send the mail 
                    //& call service etc to update the admin of current status of the watcher.
                    //this will be called only once in a watcher!
                    watcher.BeginWatch();
                    hasWatchBegin = true;
                }
            }
        }
        catch (Exception ex)
        {
            //Watcher has thrown an exception. 
            //Again, do the following operations
            //*********************
            //SendEmail();
            //LogIntoFile();
            //CallService();
        }
    }
4

2 回答 2

2

如果您使您的电子邮件、日志记录和 Web 服务调用线程安全,您可以将引用作为闭包发送到每个接收器的代码(这是 Jon Skeet 对 c# 闭包的出色解释)到监控任务中。这是您需要启动多个任务的示例:

...
void Email(string message){}

void Log(string message){}

void CallWebService(string message){}


void RunMonitoringTask()
{
    var task = Task.TaskFactory.StartNew(() =>
    {
        string message = Monitor();
        if( ShouldNotify(message))
           {
              Email(mesasge);
              Log(message);
              CallWebService(message);
           }
    }
)
}
...

编辑

与无限监视器循环在必要时触发任务:

...
void Email(string message){}

void Log(string message){}

void CallWebService(string message){}


void Monitor()
{
    while(true)
    {
          string message = Monitor();
          if(ShouldNotify(message))
          { 
              var task = Task.TaskFactory.StartNew(() =>
              {
                  Email(mesasge);
                  Log(message);
                  CallWebService(message);
              }
         }
    }
)
}
...

至于如何实现这些类,我推荐一种方法,其中每个接收器都接受消息,然后将其卸载到自己的处理线程/任务中,以避免阻塞您的监视任务并阻止其他通知。

于 2013-05-09T14:58:52.190 回答
0

Progress课程非常适合这项任务。这是一种允许长时间运行的进程通知某人(通常是调用者)该操作的当前进度的方法。

Progress<string> progress = new Progress<string>();
progress.ProgressChanged += (s, data) => Console.WriteLine(data);

for (int i = 0; i < 2; i++)
    Task.Run(() => DoWork(progress));

public static void DoWork(IProgress<string> progress)
{
    int i = 0;
    while (true)
    {
        Thread.Sleep(500);//placeholder for real work
        progress.Report(i++.ToString());
    }
}

如果您有不同类型的信息要在不同时间报告,那么只需将多个IProgress实例传递给 worker 方法。(或者,如果您同时报告几种类型数据的进度,则将所有数据包装在一个复合对象中。)

另请注意,这能够处理您所说的需要的同步。 Progress实例在创建时捕获SynchronizationContext.Current它创建时的值,并将进度更改事件的所有事件处理程序编组到该同步上下文中。因此,如果您的应用程序已经有一个上下文(即来自桌面应用程序的 UI 上下文),那么您可以免费获得它。如果您没有(即它是一个控制台应用程序),那么您需要手动将事件处理程序与 a 同步lock,或者创建您自己的SynchrnonizationContext以设置为当前上下文。

于 2013-05-09T18:06:38.160 回答