C#(。NET 1.1)で記述されたサービスがあり、毎晩深夜にクリーンアップアクションを実行したいと考えています。すべてのコードをサービス内に含める必要があるので、これを実現する最も簡単な方法は何ですか?Thread.Sleep()
ロールオーバーする時間の使用とチェック?
C#(。NET 1.1)で記述されたサービスがあり、毎晩深夜にクリーンアップアクションを実行したいと考えています。すべてのコードをサービス内に含める必要があるので、これを実現する最も簡単な方法は何ですか?Thread.Sleep()
ロールオーバーする時間の使用とチェック?
回答:
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();
}
}
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);
実際のサービスである必要がありますか?Windowsのコントロールパネルで組み込みのスケジュールされたタスクを使用できますか?
私がこれを達成する方法はタイマーを使うことです。
サーバータイマーを実行し、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チェックにあります。
テストなどのためのフックがそこにありますが、これはあなたの経過したタイマーがそれをすべて機能させるためにどのように見えるかです。
他の人がすでに書いたように、タイマーはあなたが説明したシナリオで最良のオプションです。
正確な要件によっては、1分ごとに現在の時刻を確認する必要がない場合があります。真夜中に正確にアクションを実行する必要はないが、真夜中から1時間以内であれば、日付が変わっていないかどうかだけをチェックするというマーティンのアプローチに進むことができます。
深夜にアクションを実行する理由が、コンピューターのワークロードが低いと予想される場合は、注意が必要です。同じ仮定が他のユーザーによって行われることが多く、突然、0:00から0の間に100のクリーンアップアクションが開始されます。 :01 am
その場合は、別の時間にクリーンアップを開始することを検討する必要があります。私は通常、これらのことを時計の時間ではなく、30分に行います(1.30が私の個人的な好みです)
タイマーを使用することをお勧めしますが、分ではなく45秒ごとにチェックするように設定してください。そうしないと、負荷が高く、特定の分のチェックが見落とされる状況に遭遇する可能性があります。タイマーがトリガーされてからコードが実行されて現在の時刻がチェックされるまでの間に、ターゲットの分が見落とされた可能性があるためです。
ここでTaskSchedulerLibraryを試すこともできますhttp://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
抽象クラスAbstractScheduledTask
を実装し、ScheduleUtilityFactory.AddScheduleTaskToBatch
静的メソッドを呼び出します
上記の解決策が機能しないことがわかった場合は、this
クラス内にある可能性があるためです。これは、エラーメッセージに示されているように、非ジェネリック静的クラスでのみ意味を持つ拡張メソッドを意味します。クラスは静的ではありません。これは、問題のインスタンスに作用しているため、拡張メソッドとしては意味がないようですthis
。そのため、を削除してください。
これを試して:
public partial class Service : ServiceBase
{
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SetTimer();
}
private void SetTimer()
{
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//Do some thing logic here
}
protected override void OnStop()
{
// disposed all service objects
}
}