how to make service act dynamically based on servi

2020-07-26 14:31发布

问题:

hi friends i was trying to make my service act dynamically... i have set time for my service about for 2 min ,if suppose it was doin huge amount of work means it will exceeds that 2 min time limit then we need to check the service condition if work is pending means we need to run that instance until upto finish

so that i have tried this below code on googling ... i m having method were i need to cooperate in below service, can any one help me

 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
  {
  // ...
  }
 }

as of now i m doing this below logic

  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:

I have built services that operate in a similar manner before, my advice would be to NOT start and stop the service from external code. Instead, apply the Timer methodology within the service itself, which should always be running. On TimerElapsed, do work and then return to an idle state. Thus alleviating the need to start and stop.

Further, I would protect the "stop" of a service to not allow the stop if the service is "working"

Sample Code

Note: I employ a process I call "zeroing" with my timer. Zeroing, in my context, is the process of getting the events to fire on zero seconds of every minute. To do that, I first set the time to fire every second and I check to see if the seconds part of the current time is zero, once that occurs I switch the timer elapse to every minute. I do this to give myself some sanity while testing.

Also, my scheduling is configurable so every minute when it "ticks" i check my config to see if the process "should" execute. I do so with the following 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>

Finally, this code sample is for a DataSync Services, so any references to "DataMigrationService" or "DataMigrationManager" are my own custom classes and are used as an abstraction to give me an object to control within the service.

... here's the code:

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