Mam usługę napisaną w C # (.NET 1.1) i chcę, aby co wieczór wykonywała pewne czynności porządkowe o północy. Muszę zachować cały kod zawarty w usłudze, więc jaki jest najłatwiejszy sposób, aby to osiągnąć? Używanie Thread.Sleep()
i sprawdzanie przewracania się czasu?
c#
windows-services
scheduling
scheduled-tasks
ctrlalt3nd
źródło
źródło
Odpowiedzi:
Nie użyłbym Thread.Sleep (). Użyj zaplanowanego zadania (jak wspominali inni) lub ustaw licznik czasu w swojej usłudze, który jest uruchamiany okresowo (na przykład co 10 minut) i sprawdź, czy data zmieniła się od ostatniego uruchomienia:
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(); } }
źródło
Sprawdź Quartz.NET . Możesz go używać w ramach usługi Windows. Umożliwia uruchamianie zadań w oparciu o skonfigurowany harmonogram, a nawet obsługuje prostą składnię „zadania cron”. Odniosłem z tym wiele sukcesów.
Oto krótki przykład jego użycia:
// 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);
źródło
Codzienne zadanie? Wygląda na to, że powinno to być zaplanowane zadanie (panel sterowania) - tutaj nie ma potrzeby korzystania z usługi.
źródło
Czy to musi być rzeczywista usługa? Czy możesz po prostu użyć wbudowanych zaplanowanych zadań w panelu sterowania systemu Windows.
źródło
Sposób, w jaki to robię, to zegar.
Uruchom licznik czasu serwera, niech sprawdza godzinę / minutę co 60 sekund.
Jeśli jest to właściwa godzina / minuta, uruchom proces.
Właściwie to wyekstrahowałem to do klasy bazowej, którą nazywam OnceADayRunner.
Pozwól mi trochę wyczyścić kod i opublikuję go tutaj.
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(); } }
Wołowina metody znajduje się w kontroli e.SignalTime.Minute / Hour.
Są tam haczyki do testowania itp., Ale tak mógłby wyglądać Twój upływający czas, aby wszystko działało.
źródło
Jak już pisali inni, zegar jest najlepszą opcją w opisanym przez ciebie scenariuszu.
W zależności od Twoich wymagań, sprawdzanie aktualnego czasu co minutę może nie być konieczne. Jeśli nie musisz wykonywać akcji dokładnie o północy, ale w ciągu jednej godziny po północy, możesz skorzystać z podejścia Martina i sprawdzić, czy zmieniła się data.
Jeśli powodem, dla którego chcesz wykonać swoją akcję o północy, jest to, że spodziewasz się niskiego obciążenia komputera, lepiej zachowaj ostrożność: to samo założenie jest często przyjmowane przez innych i nagle masz 100 czynności porządkujących rozpoczynających się między 0:00 a 0 : 01 am
W takim przypadku powinieneś rozważyć rozpoczęcie czyszczenia w innym czasie. Zwykle robię te rzeczy nie o godzinie zegarowej, ale o pół godziny (1.30 to moje osobiste preferencje)
źródło
Sugerowałbym użycie timera, ale ustaw go tak, aby sprawdzał co 45 sekund, a nie minutę. W przeciwnym razie możesz spotkać się z sytuacjami, w których przy dużym obciążeniu sprawdzenie dla określonej minuty zostanie pominięte, ponieważ między czasem wyzwolenia timera a czasem uruchomienia kodu i sprawdzenia aktualnego czasu możesz przegapić docelową minutę.
źródło
Możesz także wypróbować TaskSchedulerLibrary tutaj http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
Zaimplementuj klasę abstrakcyjną
AbstractScheduledTask
i wywołajScheduleUtilityFactory.AddScheduleTaskToBatch
metodę statycznąźródło
Dla tych, dla których powyższe rozwiązania nie działają, dzieje się tak dlatego, że możesz mieć
this
wewnątrz swojej klasy, co implikuje metodę rozszerzającą, która, jak mówi komunikat o błędzie, ma sens tylko w nieogólnej klasie statycznej. Twoja klasa nie jest statyczna. Wydaje się, że nie ma to sensu jako metoda rozszerzenia, ponieważ działa w danej instancji, więc usuń rozszerzeniethis
.źródło
Spróbuj tego:
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 } }
źródło