如何使服务根据服务运行条件动态动作

时间:2011-07-06 10:01:11

标签: c# asp.net vb.net

朋友们,我试图让我的服务动态行动......我已经为我的服务设定了大约2分钟的时间,如果假设它做了大量的工作意味着它将超过2分钟的时间限制那么我们需要检查服务条件是否工作正在等待意味着我们需要运行该实例直到完成

所以我在谷歌搜索下面的代码...我有方法是我需要在以下服务合作,任何人都可以帮助我

 public static void StartService(string serviceName, int timeoutMilliseconds)
   {
  ServiceController service = new ServiceController(serviceName);
  try
   {
   TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);

    service.Start();
    service.WaitForStatus(ServiceControllerStatus.Running, timeout);
   }
   catch
  {
  // ...
  }
 }

截至目前,我正在逻辑

下面这样做
  protected override void OnStart(string[] args)
    {
        // my service name 
        Workjob("FTSCSVGenerator");
        // ad 1: handle Elapsed event and CsvGenFromDatabase is method which i have to executed
        timerjob.Elapsed += new ElapsedEventHandler(CsvGenFromDatabase);
       // ad 2: set interval to 1 minute (= 60,000 milliseconds)
      timerjob.Interval = Convert.ToDouble(DueTime);
      //  ////ad 3: enabling the timer
      timerjob.Enabled = true;
      eventLog1.WriteEntry("my service started");
    }

    protected override void OnStop()
    {           
        eventLog1.WriteEntry("my service stopped");
    }


    private void Workjob(string servicename )
    {
        ServiceController servicecsv = new ServiceController(servicename);


         if ((servicecsv.Status.Equals(ServiceControllerStatus.Stopped)) || (servicecsv.Status.Equals(ServiceControllerStatus.StopPending)))
         {
             // Start the service if the current status is stopped.                 
             servicecsv.Start( );               
         }
         else
         {
             // Stop the service if its status is not set to "Stopped".                 
             servicecsv.Stop();
         }  


    }

1 个答案:

答案 0 :(得分:1)

我之前构建过以类似方式运行的服务,我的建议是不要从外部代码启动和停止服务。相反,在服务本身中应用Timer方法,该方法应始终运行。在TimerElapsed上,执行工作然后返回空闲状态。从而减轻了启动和停止的需要。

此外,如果服务“正常”,我会保护服务的“停止”不允许停止

示例代码

注意:我使用我的计时器称为“归零”的过程。在我的上下文中,归零是在每分钟的零秒内触发事件的过程。要做到这一点,我首先设置每秒触发的时间,然后检查当前时间的秒部分是否为零,一旦发生这种情况,我将计时器的时间切换为每分钟。我这样做是为了在测试时给自己一些理智。

此外,我的日程安排是可配置的,所以每当它“滴答”我检查我的配置以查看过程是否“应该”执行时。我这样做是使用以下Xml Schema:

    <?xml version="1.0" encoding="utf-8"?>
<ScheduleDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ScheduleInterval>1</ScheduleInterval>
  <ScheduleUnits>min</ScheduleUnits>
  <DailyStartTime>1753-01-01T08:00:00</DailyStartTime>
  <ExcludedWeekDays>
    <string>Sunday</string>
    <string>Saturday</string>
  </ExcludedWeekDays>
  <ExcludedDates>
    <string>12/25</string>
    <string>02/02</string>
    <string>03/17</string>
  </ExcludedDates>
  <DailyRunTimes>
   <!-- code ommitted for size // -->
  </DailyRunTimes>
</ScheduleDefinition>

最后,此代码示例用于DataSync服务,因此对“DataMigrationService”或“DataMigrationManager”的任何引用都是我自己的自定义类,并用作抽象来为我提供在服务中控制的对象。

...这是代码:

    using System;
using System.Diagnostics;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using DataMigration.Configuration;
using DataMigration.ObjectModel;

namespace DataSyncService
{
    public partial class DataSyncService : ServiceBase
    {
        #region Private Members
        private System.Timers.Timer _timer = null;
        private SimpleScheduleManager.ScheduleDefinition _definition = null;
        private DataMigrationManager _manager = new DataMigrationManager();
        #endregion

        #region Constructor(s)
        public DataSyncService()
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolver.Resolve);
            InitializeComponent();
        }
        ~DataSyncService()
        {
            _manager = null;
            _definition = null;
            _timer = null;
        }
        #endregion

        #region Public Method(s)
        protected override void OnStart(string[] args)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            _manager.ProcessMonitor.Logger.Debug("Assembly Version: ", assembly.GetName().FullName);
            assembly = null;

            SetScheduleFromConfigurationFile();

            _timer = new System.Timers.Timer(1000);
            _timer.AutoReset = true;
            _timer.Enabled = true;
            _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_ZeroingProcess);
            _timer.Start();
        }

        protected override void OnStop()
        {
            _timer.Stop();
            _timer.Enabled = false;
            _timer = null;

            // block if the Process is active!
            if (_manager.State == DataMigrationState.Processing)
            {
                // I invented my own CancellableAsyncResult (back in the day), now you can use CancellationTokenSource
                CancellableAsyncResult result = _manager.RequestCancel() as CancellableAsyncResult;
                while (!result.IsCompleted) { Thread.Sleep(ServiceConstants.ThreadSleepCount); }
                try
                {
                    result.EndInvoke();
                }
                catch (Exception ex)
                {
                    ProcessMonitorMessage message = ProcessMonitorMessage.GetErrorOccurredInstance();
                    message.EventType = ProcessMonitorEventType.ProcessAlert;
                    message.Severity = ProcessMessageSeverity.ErrorStop;
                    message.SubjectLine = "Error while stopping service. ";
                    message.EventDescription = ex.Message;

                    _manager.ProcessMonitor.ReportError(message);
                }
            }
        }
        #endregion

        #region Private Method(s)
        private bool MigrationIsScheduledToRunNow()
        {
            DateTime now = DateTime.Now;
            foreach (string dowString in _definition.ExcludedWeekDays)
            {
                if (now.DayOfWeek.ToString().Equals(dowString))
                {
                    Trace.WriteLine("Today is " + dowString, "Excluded by Schedule definition");
                    return false;
                }
            }

            foreach (string datePart in _definition.ExcludedDates)
            {
                string dateString = datePart + "/2008"; // 2008 is a leap year so it "allows" all 366 possible dates.
                DateTime excludedDate = Convert.ToDateTime(dateString);
                if (excludedDate.Day.Equals(now.Day) && excludedDate.Month.Equals(now.Month))
                {
                    Trace.WriteLine("Today is " + datePart, "Excluded by Schedule definition");
                    return false;
                }
            }

            foreach (DateTime runTime in _definition.DailyRunTimes)
            {
                if (runTime.Hour.Equals(now.Hour) && runTime.Minute.Equals(now.Minute))
                {
                    Trace.WriteLine("Confirmed Scheduled RunTime: " + runTime.TimeOfDay.ToString(), "Included by Schedule definition");
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Load Scheduling Configuration Options from the Xml Config file.
        /// </summary>
        private void SetScheduleFromConfigurationFile()
        {
            string basePath = AppDomain.CurrentDomain.BaseDirectory;
            if (basePath.EndsWith("\\")) { basePath = basePath.Substring(0, basePath.Length - 1); }
            string path = string.Format("{0}\\Scheduling\\scheduledefinition.xml", basePath);
            _manager.ProcessMonitor.Logger.Debug("Configuration File Path", path);

            XmlSerializer serializer = new XmlSerializer(typeof(SimpleScheduleManager.ScheduleDefinition));
            XmlTextReader reader = new XmlTextReader(path);
            reader.WhitespaceHandling = WhitespaceHandling.None;
            _definition = serializer.Deserialize(reader) as SimpleScheduleManager.ScheduleDefinition;

            reader = null;
            serializer = null;

        }
        #endregion

        #region Timer Events
        private void _timer_ZeroingProcess(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (DateTime.Now.Second.Equals(0))
            {
                _timer.Interval = 60000;
                _timer.Elapsed -= new System.Timers.ElapsedEventHandler(_timer_ZeroingProcess);
                _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
                _timer_Elapsed(sender, e);
            }
        }

        private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            _manager.ProcessMonitor.Logger.Info("Timer Elapsed", DateTime.Now.ToString());
            if (MigrationIsScheduledToRunNow())
            {
                switch (_manager.State)
                {
                    case DataMigrationState.Idle:
                        _manager.ProcessMonitor.Logger.Info("DataMigration Manager is idle. Begin Processing.");
                        _manager.BeginMigration();
                        break;
                    case DataMigrationState.Failed:
                        _manager.ProcessMonitor.Logger.Warn("Data Migration is in failed state, Email <NotificationRecipients> alerting them.");
                        break;
                    default:
                        _manager.ProcessMonitor.Logger.Warn("DataMigration Manager is still processing.  Skipping this iteration.");
                        break;
                }
            }
        }

        #endregion
    }
}