Служба Windows работает, но прекращает обработку через два дня

Я видел довольно много сообщений по этой проблеме, но не похоже на мои критерии.

Сказав это, это первый, который я создал, который "нужен" для выполнения огромного количества логики. Все работает отлично в течение нескольких дней, но после этого логика перестает работать без регистрации в средстве просмотра событий и не запускает электронную почту (исключения).

Мне интересно, не ошибается ли моя логика... Ищите советы и указатели.

public partial class QuayService : ServiceBase
{
    private System.Timers.Timer m_mainTimer;
    private bool m_timerTaskSuccess;
    private Email _email;
    public QuayService()
    {
        InitializeComponent();
        _email = new Email();
    }

    protected override void OnStart(string[] args)
    {
        try
        {
            // Create and start a timer.
            m_mainTimer = new System.Timers.Timer();
            m_mainTimer.Interval = 5000;   // every 5 seconds
            m_mainTimer.Elapsed += m_mainTimer_Elapsed;
            m_mainTimer.AutoReset = false;  // makes it fire only once
            m_mainTimer.Start(); // Start

            m_timerTaskSuccess = false;

            _email.SendEmail("Quay", "(Shopify)Quay Service Started",
                "(Shopify)Quay Service Successfuly Started");

            EventLog.WriteEntry("(Shopify)Quay Service Started...");
        }
        catch (Exception ex)
        {
            // Log/Send Email
            _email.SendEmail("Quay", "Error starting (Shopify)Quay Service", ex.Message + " " + 
                ex.InnerException.Message);

            EventLog.WriteEntry("Error starting (Shopify)Quay service and timer..." + ex.Message + " " +
                ex.InnerException.Message);
        }
    }

    protected override void OnStop()
    {
        try
        {
            // Service stopped. Also stop the timer.
            m_mainTimer.Stop();
            m_mainTimer.Dispose();
            m_mainTimer = null;

            _email.SendEmail("Quay", "(Shopify)Quay Service stopped",
                "(Shopify)Quay Service Successfuly Stopped");

            EventLog.WriteEntry("(Shopify)Quay Service stopped...");
        }
        catch (Exception ex)
        {
            _email.SendEmail("Quay", "Error stopping (Shopify)Quay Service", ex.Message + " " +
                ex.InnerException.Message);

            // Log/Send Email
            EventLog.WriteEntry("Error stopping (Shopify)Quay timer and service..." + ex.Message + " " +
                ex.InnerException.Message);
        }
    }

    void m_mainTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        try
        {
            var orderUoW = new OrderUoW();
            orderUoW.Create();

            m_timerTaskSuccess = true;
        }
        catch (Exception ex)
        {
            //Error with timer elapsed
            m_timerTaskSuccess = false;

            _email.SendEmail("Quay", "Error creating (Shopify)Quay order(s)", ex.Message + " " +
                ex.InnerException.Message);

            EventLog.WriteEntry("Error creating (Shopify)Quay order(Time elapsed event)..." + ex.Message
                + " " + ex.InnerException.Message);
        }
        finally
        {
            if (m_timerTaskSuccess)
            {
                m_mainTimer.Start();
            }
        }
    }
}

Чтобы добраться до этого момента, я "googled" и "SO'ed", чтобы найти наилучшее использование таймера... У меня также есть наивный тестовый уровень, который воспроизводит то, что в сервисе, я могу пробежать этот штраф без любые исключения, но этот меня заводит.

Любая помощь действительно ценится!

//EDIT

Небольшое объяснение:

var orderUoW = new OrderUoW(); 
orderUoW.Create();

OrderUoW - это класс в моей службе, который наследует от BatchOrder, который отвечает за множество действий, включая подключение к двум базам данных и опрос API-интерфейса shopify... OrderUoW - это просто отделить от бизнес-уровня, но предоставляя доступ к методам "x".

Все работает безупречно в течение двух дней, но, похоже, останавливается. Я не попадаю в пределы запросов в пределах магазина... так что в данный момент я в недоумении.

Ответ 1

После многих моментов царапин моей головы и крайнего раздражения с MS Timer Bug.

Не только проглотил исключения, таймер не поднял это событие! Мое служение висело, что было особенно сложно, потому что оно также проглотило исключения.

Теперь я пошел по пути реализации половины Threading.Timer

  • Не используйте System.Windows.Forms.Timer, потому что он не будет работать (это имеет смысл).

  • Не используйте System.Threading.Timer, потому что он не работает, вместо этого используйте System.Timers.Timer.

  • Не используйте System.Timers.Timer, потому что он не работает, вместо этого используйте System.Threading.Timer.

Связанный с нами вопрос.

Я действительно не мог беспокоиться о проблемах, связанных с этими шагами, поскольку моя цель состояла в том, чтобы сосредоточиться на бизнес-логике. Поэтому я принял решение использовать Quartz.Net.

Это облегчило мою жизнь и, похоже, отлично работает! 45-60 минут работы.

Основная настройка:

1, Nuget > Quartz

2, Новая папка (ы) > QuartzComponents > Работа и расписание

введите описание изображения здесь

3, добавлены OrderJob.cs и OrderJobSchedule.cs в соответствующие папки

Логика OrderJob.cs:

 public sealed class OrderJob : IJob
 {
    public void Execute(IJobExecutionContext context)
    {
            var orderUoW = new OrderUoW();
            orderUoW.Create();
     }
  }

Обратите внимание, что он создает экземпляр моего UoW?!? логики, что он попадет на каждый проход.

Логика OrderJobSchedule.cs:

   public sealed class OrderJobSchedule
    {
        public void Start()
        {
            IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
            scheduler.Start();

            IJobDetail job = JobBuilder.Create<OrderJob>().Build();

            ITrigger trigger = TriggerBuilder.Create()
                   .WithSimpleSchedule(a => a.WithIntervalInSeconds(15).RepeatForever())
                   .Build();

            scheduler.ScheduleJob(job, trigger);
        }

        public void Stop()
        {
            IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
            scheduler.Shutdown();
        }
    }

Здесь много волшебства, но для акцента на:

JobBuilder.Create<OrderJob>().Build();

a.WithIntervalInSeconds(15).RepeatForever()

Теперь, когда нам нужно добавить логику в "кишки" сервиса:

public partial class QuayService : ServiceBase
    {
        OrderJobSchedule scheduler;
        public QuayService()
        {
            InitializeComponent();
        }
        protected override void OnStart(string[] args)
        {
            try
            {
                scheduler = new OrderJobSchedule();
                scheduler.Start();

                SendEmail("(Shopify)Quay Service Started",
                    "(Shopify)Quay Service Successfuly Started");
            }
            catch (Exception ex)
            {
                ProcessException(ex, "Error starting (Shopify)Quay Service");
                EventLog.WriteEntry("Error starting (Shopify)Quay service and timer..." + ex.Message);
            }
        }
        protected override void OnStop()
        {
            try
            {
                if (scheduler != null)
                {
                    scheduler.Stop();
                }

                SendEmail("(Shopify)Quay Service stopped",
                    "(Shopify)Quay Service Successfuly Stopped");
            }
            catch (Exception ex)
            {
                ProcessException(ex, "Error stopping (Shopify)Quay Service");
                EventLog.WriteEntry("Error stopping (Shopify)Quay timer and service..." + ex.Message);
            }
        }
        private void SendEmail(string subject, string body)
        {
            new Email().SendErrorEmail("Quay", subject, body);
        }
        private void ProcessException(Exception ex,
            string customMessage)
        {
            var innerException = "";
            if (ex.InnerException != null)
                innerException = (!string.IsNullOrWhiteSpace(ex.InnerException.Message)) ? ex.InnerException.Message : "";


            new Email().SendErrorEmail("Quay", customMessage, 
                ex.Message + " " + innerException);
        }
    } 

Очень легко настроить и решить мой ужасный опыт с помощью Timers.Timer Пока я не исправил основную проблему, я придумал решение и получил работоспособную систему без ошибок.

Обратите внимание на будущих читателей НЕ ИСПОЛЬЗУЙТЕ System.Timers.Timer, если вы не готовы добавить "хакерское" исправление.