如何使服务根据服务运行情况动态行动

本文关键字:服务 动态 情况 何使 运行 | 更新日期: 2023-09-27 18:01:32

朋友们,我想让我的服务动态运行…我为我的服务设置了大约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();
         }  

    }

如何使服务根据服务运行情况动态行动

我以前构建过以类似方式运行的服务,我的建议是不要从外部代码启动和停止服务。相反,应该在服务本身中应用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 Services的,因此任何对"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
    }
}