web-dev-qa-db-ja.com

タスクを毎日実行するようにC#Windowsサービスをスケジュールするにはどうすればよいですか?

C#(.NET 1.1)で記述されたサービスがあり、毎晩深夜にクリーンアップアクションを実行したい。サービスに含まれるすべてのコードを保持する必要があるので、これを達成する最も簡単な方法は何ですか? Thread.Sleep()の使用とロールオーバー時間の確認?

83
ctrlalt3nd

Thread.Sleep()は使用しません。スケジュールされたタスクを使用するか(他の人が述べたように)、サービス内でタイマーを設定し、定期的に(たとえば10分ごとに)起動し、最後の実行以降に日付が変更されたかどうかを確認します:

private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);

protected override void OnStart(string[] args)
{
    _timer = new Timer(10 * 60 * 1000); // every 10 minutes
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
    _timer.Start();
    //...
}


private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // ignore the time, just compare the date
    if (_lastRun.Date < DateTime.Now.Date)
    {
        // stop the timer while we are running the cleanup task
        _timer.Stop();
        //
        // do cleanup stuff
        //
        _lastRun = DateTime.Now;
        _timer.Start();
    }
}
87
M4N

Quartz.NET をご覧ください。 Windowsサービス内で使用できます。設定されたスケジュールに基づいてジョブを実行することができ、単純な「cronジョブ」構文もサポートします。私はそれで多くの成功を収めてきました。

その使用法の簡単な例を次に示します。

// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();

// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));

// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
    "trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");

// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
71
jeremcc

毎日の仕事ですか?スケジュールされたタスク(コントロールパネル)にすぎないように思えますが、ここではサービスは必要ありません。

21
Marc Gravell

実際のサービスである必要がありますか? Windowsのコントロールパネルで組み込みのスケジュールされたタスクを使用できますか。

15
Ian Jacobs

これを実現する方法は、タイマーを使用することです。

サーバータイマーを実行し、60秒ごとに時間/分をチェックします。

適切な時間/分であれば、プロセスを実行します。

実際には、これをOnceADayRunnerという基本クラスに抽象化しています。

コードを少し整理して、ここに投稿します。

    private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        using (NDC.Push(GetType().Name))
        {
            try
            {
                log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
                log.DebugFormat("IsTestMode: {0}", IsTestMode);

                if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
                {
                    log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
                    OnceADayTimer.Enabled = false;
                    OnceADayMethod();
                    OnceADayTimer.Enabled = true;

                    IsTestMode = false;
                }
                else
                {
                    log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
                }
            }
            catch (Exception ex)
            {
                OnceADayTimer.Enabled = true;
                log.Error(ex.ToString());
            }

            OnceADayTimer.Start();
        }
    }

メソッドの牛肉はe.SignalTime.Minute/Hourチェックにあります。

そこにはテストなどのためのフックがありますが、これは経過したタイマーがすべて動作するように見えるものです。

3
CubanX

他の人がすでに書いたように、タイマーはあなたが説明したシナリオで最良のオプションです。

正確な要件に応じて、現在時刻を毎分チェックする必要はありません。真夜中にアクションexactlyを実行する必要はないが、真夜中から1時間以内であれば、 Martinのアプローチ 日付が変更されたかどうかのみをチェックします。

真夜中にアクションを実行する理由がコンピューターのワークロードが少ないことを期待している場合、注意が必要です:同じ仮定が他の人によってしばしば行われ、突然0時から0時の間に100のクリーンアップアクションが開始されます:午前1時.

その場合は、別の時間にクリーンアップを開始することを検討する必要があります。私は通常、これらのことを時計の時間ではなく、30分で行います(私の好みは午前1.30です)

2
Treb

タイマーを使用することをお勧めしますが、分ではなく45秒ごとにチェックするように設定します。そうしないと、タイマーがトリガーされてからコードが実行されて現在の時刻をチェックするまでの間に、特定の分のチェックが失われる可能性があります。

1
GWLlosa

こちらからTaskSchedulerLibraryを試すこともできます http://visualstudiogallery.msdn.Microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8

抽象クラスAbstractScheduledTaskを実装し、ScheduleUtilityFactory.AddScheduleTaskToBatch静的メソッドを呼び出します

0
Samuel

上記の解決策が機能しない場合は、クラス内にthisが含まれている可能性があります。これは、エラーメッセージが示すように、非ジェネリックな静的クラスでのみ意味のある拡張メソッドを意味します。クラスは静的ではありません。これは、問題のインスタンスに作用するため、拡張メソッドとして意味のあるものではないようです。そのため、thisを削除してください。

0
Fandango68