Служба Windows для запуска функции в указанное время
Я хотел запустить службу Windows для ежедневной работы функции в определенное время.
Какой метод я должен рассмотреть, чтобы реализовать это? Таймер или использование потоков?
Ответы
Ответ 1
(1) При первом запуске установите _timer.Interval в миллисекундах между началом службы и временем расписания. Этот образец устанавливает время расписания до 7:00 утра как _scheduleTime = DateTime.Today.AddDays(1).AddHours(7);
(2) В Timer_Elapsed, reset _timer.Interval до 24 часов (в миллисекундах), если текущий интервал не равен 24 часам.
System.Timers.Timer _timer;
DateTime _scheduleTime;
public WinService()
{
InitializeComponent();
_timer = new System.Timers.Timer();
_scheduleTime = DateTime.Today.AddDays(1).AddHours(7); // Schedule to run once a day at 7:00 a.m.
}
protected override void OnStart(string[] args)
{
// For first time, set amount of seconds between current time and schedule time
_timer.Enabled = true;
_timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// 1. Process Schedule Task
// ----------------------------------
// Add code to Process your task here
// ----------------------------------
// 2. If tick for the first time, reset next run to every 24 hours
if (_timer.Interval != 24 * 60 * 60 * 1000)
{
_timer.Interval = 24 * 60 * 60 * 1000;
}
}
Ответ 2
Используйте Windows, встроенный в Планировщик заданий (http://windows.microsoft.com/en-us/windows7/schedule-a-task) или Quartz.net.
Если... у вас есть служба, которая выполняет большую часть другой обработки и должна работать постоянно, и в этом случае может потребоваться Таймер.
Ответ 3
Хороший ответ (я использовал ваш код), но одна проблема с этой строкой:
_timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
Если DateTime.now позже, чем scheduleTime, вы попадёте отрицательно, и это приведет к возникновению исключения при назначении таймера .Interval.
Я использовал:
if (DateTime.now > scheduleTime)
scheduleTime = scheduleTime.AddHours(24);
Затем выполняем вычитание.
Ответ 4
Вы уверены, что вам нужна услуга, которая работает только один раз в день?
Возможно, расписание задач Windows будет лучшим решением?
Ответ 5
private static double scheduledHour = 10;
private static DateTime scheduledTime;
public WinService()
{
scheduledTime = DateTime.Today.AddHours(scheduledHour);//setting 10 am of today as scheduled time- service start date
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
DateTime now = DateTime.Now;
if (scheduledTime < DateTime.Now)
{
TimeSpan span = now - DateTime.Now;
scheduledTime = scheduledTime.AddMilliseconds(span.Milliseconds).AddDays(1);// this will set scheduled time to 10 am of next day while correcting the milliseconds
//do the scheduled task here
}
}
Ответ 6
Вы можете сделать это с помощью потока и события; таймер не требуется.
using System;
using System.ServiceProcess;
using System.Threading;
partial class Service : ServiceBase
{
Thread Thread;
readonly AutoResetEvent StopEvent;
public Service()
{
InitializeComponent();
StopEvent = new AutoResetEvent(initialState: false);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
StopEvent.Dispose();
components?.Dispose();
}
base.Dispose(disposing);
}
protected override void OnStart(string[] args)
{
Thread = new Thread(ThreadStart);
Thread.Start(TimeSpan.Parse(args[0]));
}
protected override void OnStop()
{
if (!StopEvent.Set())
Environment.FailFast("failed setting stop event");
Thread.Join();
}
void ThreadStart(object parameter)
{
while (!StopEvent.WaitOne(Timeout(timeOfDay: (TimeSpan)parameter)))
{
// do work here...
}
}
static TimeSpan Timeout(TimeSpan timeOfDay)
{
var timeout = timeOfDay - DateTime.Now.TimeOfDay;
if (timeout < TimeSpan.Zero)
timeout += TimeSpan.FromDays(1);
return timeout;
}
}