C#(.NET 1.1)で記述されたサービスがあり、毎晩深夜にクリーンアップアクションを実行するようにしたいと考えています。すべてのコードをサービス内に含める必要があるので、これを実現する最も簡単な方法は何ですか?Thread.Sleep()
ロールオーバーする時間を使用してチェックしますか?
10 に答える
私は 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
これを試して:
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
}
}