2009-02-02 25 views
76

Tôi có một dịch vụ được viết bằng C# (.NET 1.1) và muốn nó thực hiện một số hành động dọn dẹp vào nửa đêm mỗi đêm. Tôi phải giữ tất cả các mã trong dịch vụ, vậy cách dễ nhất để thực hiện điều này là gì? Sử dụng Thread.Sleep() và kiểm tra thời gian di chuyển qua?Tôi có thể lên lịch cho Dịch vụ Windows C# để thực hiện nhiệm vụ hàng ngày như thế nào?

+8

Bạn thực sự muốn thực hiện một quá trình .NET mà ngồi trong bộ nhớ, tất cả các ngày, và làm điều gì đó vào lúc nửa đêm? Tại sao chính xác bạn không thể, khi cài đặt công cụ của bạn, thiết lập một sự kiện hệ thống kích hoạt vào lúc nửa đêm (hoặc một số thời gian cấu hình khác) khởi động ứng dụng của bạn, thực hiện điều đó, rồi biến mất? –

+5

Tôi biết tôi sẽ hơi tức giận nếu tôi phát hiện ra rằng tôi đã có một dịch vụ được quản lý tiêu thụ 20-40 megabyte bộ nhớ, chạy mọi lúc, điều đó không làm gì ngoại trừ một lần một ngày. :) –

+0

[liên kết] trùng lặp của nó (http://stackoverflow.com/questions/503564/how-might-i-schedule-ac-sharp-windows-service-to-perform-a-task-daily) – csa

Trả lời

83

tôi sẽ không sử dụng Thread.Sleep(). Hoặc sử dụng một nhiệm vụ theo lịch trình (như những người khác đã đề cập), hoặc thiết lập một bộ đếm thời gian bên trong dịch vụ của bạn, mà cháy theo định kỳ (mỗi 10 phút chẳng hạn) và kiểm tra xem ngày đã thay đổi kể từ khi chạy lần cuối:

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(); 
    } 
} 
+27

Nó sẽ không có ý nghĩa hơn để chỉ cần thiết lập bộ đếm thời gian hết hạn vào lúc nửa đêm, thay vì thức dậy mỗi phút để kiểm tra thời gian? – Kibbee

+11

@Kibbee: có thể nếu dịch vụ không hoạt động vào lúc nửa đêm (vì bất kỳ lý do gì), thì bạn có thể muốn thực hiện tác vụ ngay khi dịch vụ chạy lại. – M4N

+4

Sau đó, bạn nên thêm một số mã trong khi khởi động dịch vụ để tìm hiểu xem bạn có nên chạy ngay lập tức không, vì dịch vụ không chạy, và nó sẽ là như vậy. Bạn không nên kiểm tra mỗi 10 phút liên tục.Kiểm tra xem bạn có nên chạy khi khởi động không, và sau đó nếu không tìm ra lần sau để chạy. sau đó, và thiết lập một bộ đếm thời gian cho tuy nhiên bạn cần. – Kibbee

3

Cách tôi thực hiện việc này là với bộ hẹn giờ.

Chạy bộ hẹn giờ máy chủ, để nó kiểm tra Giờ/Phút sau mỗi 60 giây.

Nếu đó là Giờ/Phút phù hợp, hãy chạy quy trình của bạn.

Tôi thực sự có điều này trừu tượng ra thành một lớp cơ sở tôi gọi OnceADayRunner.

Hãy để tôi làm sạch mã một chút và tôi sẽ đăng nó ở đây.

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(); 
     } 
    } 

Thịt bò của phương pháp nằm trong kiểm tra e.SignalTime.Minute/Hour.

Có móc trong đó để thử nghiệm, v.v. nhưng đây là những gì bộ đếm thời gian trôi qua của bạn có thể trông giống như để làm cho nó tất cả các công việc.

+0

Một chút chậm trễ do một máy chủ bận rộn có thể làm cho nó bỏ lỡ giờ + phút. –

+1

Đúng. Khi tôi làm điều này, tôi đã kiểm tra: Bây giờ là lúc lớn hơn 00:00? Nếu vậy, có hơn 24 giờ kể từ lần cuối tôi chạy công việc không? Nếu vậy, hãy chạy công việc, nếu không hãy đợi lại. – ZombieSheep

15

Dịch vụ có phải là dịch vụ thực tế không? Bạn có thể sử dụng các tác vụ được lập lịch trong bảng điều khiển cửa sổ không.

+0

Vì dịch vụ đã tồn tại, có thể dễ dàng thêm chức năng ở đó. – M4N

+1

Việc chuyển đổi dịch vụ có mục đích hẹp như thế này thành ứng dụng bảng điều khiển sẽ không đáng kể. –

+7

Ông đã nói, "Tôi phải giữ tất cả các mã chứa trong dịch vụ". Tôi không cảm thấy nó là cần thiết để đặt câu hỏi các yêu cầu ban đầu. Nó phụ thuộc, nhưng đôi khi có những lý do rất tốt để sử dụng một dịch vụ trên một nhiệm vụ theo lịch trình. – jeremcc

19

Công việc hàng ngày? Âm thanh như nó chỉ nên là một nhiệm vụ theo lịch trình (bảng điều khiển) - không cần một dịch vụ ở đây.

69

Khám phá Quartz.NET. Bạn có thể sử dụng nó trong một dịch vụ Windows. Nó cho phép bạn chạy một công việc dựa trên một lịch trình được cấu hình, và nó thậm chí còn hỗ trợ cú pháp "cron job" đơn giản. Tôi đã có rất nhiều thành công với nó.

Dưới đây là một ví dụ nhanh của việc sử dụng của nó:

// 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); 
+2

Một gợi ý tốt - ngay sau khi bạn làm điều gì đó thậm chí còn phức tạp hơn so với công cụ hẹn giờ cơ bản bạn nên xem xét Quartz. – serg10

+1

Quartz rất dễ sử dụng, tôi cho rằng ngay cả đối với một tác vụ siêu đơn giản, chỉ cần tiếp tục và sử dụng nó. Nó sẽ cung cấp cho khả năng dễ dàng điều chỉnh lịch trình. –

+0

Siêu đơn giản là không thực sự? Hầu hết các newbies sẽ bắt gặp vấn đề này ở đây http://stackoverflow.com/questions/24628372/quartz-job-scheduler-in-windows-service – batmaci

1

tôi sẽ đề nghị bạn sử dụng một bộ đếm thời gian, nhưng đặt nó để kiểm tra mỗi 45 giây, không phải phút. Nếu không, bạn có thể gặp các tình huống có tải nặng, việc kiểm tra một phút cụ thể bị bỏ qua, vì giữa thời gian bộ hẹn giờ kích hoạt và thời gian mã của bạn chạy và kiểm tra thời gian hiện tại, bạn có thể đã bỏ lỡ phút mục tiêu.

+0

Nếu bạn không kiểm tra để đảm bảo rằng nó chưa chạy một lần, có khả năng bạn có thể nhấn 00:00 hai lần nếu bạn đang kiểm tra bao giờ 45 giây. –

+0

Điểm tốt. Vấn đề này có thể tránh được bằng cách gọi Sleep (15000) ở cuối thủ tục kiểm tra. (hoặc có lẽ 16000 ms, chỉ để được ở bên an toàn ;-) – Treb

+0

Tôi đồng ý, bạn nên kiểm tra xem nó đã chạy chưa, bất kể thời gian hẹn giờ bạn chọn là bao nhiêu. – GWLlosa

2

Như những người khác đã viết, bộ hẹn giờ là lựa chọn tốt nhất trong kịch bản bạn mô tả.

Tùy thuộc vào yêu cầu chính xác của bạn, kiểm tra thời gian hiện tại mỗi phút có thể không cần thiết. Nếu bạn không cần thực hiện tác vụ chính xác vào lúc nửa đêm, nhưng chỉ trong vòng một giờ sau nửa đêm, bạn có thể truy cập Martin's approach chỉ kiểm tra xem ngày đã thay đổi chưa.

Nếu lý do bạn muốn thực hiện hành động vào lúc nửa đêm là bạn mong đợi một khối lượng công việc thấp trên máy tính, hãy cẩn thận hơn: Giả định này thường được thực hiện bởi người khác và đột nhiên bạn có 100 hành động dọn dẹp khởi động giữa 0 : 00 và 0:01 sáng

Trong trường hợp đó, bạn nên cân nhắc việc bắt đầu dọn dẹp vào một thời điểm khác. Tôi thường làm những điều không vào giờ đồng hồ, nhưng ít tiếng rưỡi (01:30 là sở thích cá nhân của tôi)

-2

Hãy thử điều này:

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 
    } 
} 
-1

đây là mảnh của tôi về mã mà hoạt động:

protected override void OnStart(string[] args) 
    { 
      timer = new Timer(); //Initialize the globally declared timer 
      //SETTING THE INTERVAL FROM CONFIG FILE (10 SECONDS) 
      timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["TimerInterval"]); 
      timer.Enabled = true; 
      timer.Elapsed += timer_Elapsed;   
    } 

Trong trường hợp trôi qua, bạn có thể làm điều này:

private void timer_Elapsed(object sender, ElapsedEventArgs e) 
    { 
      timer.Enabled = false;   
      string ScheduleTime = GlobalVariables.ScheduledTime;//GETTING SCHEDULED TIME FROM CONFIG IN (HH:mm) FORMAT 
      string CurrentHourMin = DateTime.Now.ToString("HH:mm");//GETTING CURRENT TIME IN HH:mm format 
      if (ScheduleTime == CurrentHourMin) 
      { 
       // YOUR CODE 
      } 
      System.Threading.Thread.Sleep(60000); //Putting thread to sleep for 60 seconds to skip the current minute to avoid re-execution of code 
      timer.Enabled = true;     
    } 
Các vấn đề liên quan