Подтвердить что ты не робот

Создание службы windows С# для опроса базы данных

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

Я не уверен, что это лучший способ сделать это, я могу найти несколько блогов об этом и этот вопрос Служба опроса - С#. Однако я опасаюсь, что они все довольно старые и, возможно, устарели.

Может ли кто-нибудь посоветовать мне о текущих советах или лучших практиках (если они есть) о том, чтобы сделать что-то подобное или указать мне в сторону более недавнего сообщения в блоге об этом. Из того, что я могу собрать, используя таймер или задачи tpl, есть два возможных способа сделать это.

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

Извините, что я могу задавать довольно много в одном вопросе, но я не совсем уверен, что я прошу.

4b9b3361

Ответ 1

Для этого используйте службу Windows. Использование запланированной задачи - это не плохая идея сама по себе, но, поскольку вы сказали, что опросы могут возникать каждые 2 минуты, вам, вероятно, лучше идти с сервисом. Служба позволит вам поддерживать состояние между опросами, и у вас будет больше контроля за временем проведения опросов. Вы сказали, что операция может занять 30 минут, как только она стартует, поэтому, возможно, вы захотите отложить опросы до завершения операции. Это немного легче сделать, когда логика запускается как служба.

В конце концов, не важно, какой механизм вы используете для создания опросов. Вы можете использовать таймер или выделенный поток/задачу, которая спит или что-то еще. Лично я считаю, что выделенный поток/задача легче работать, чем таймер для таких вещей, потому что легче контролировать интервал опроса. Кроме того, вы обязательно должны использовать механизм отмены сотрудничества, предоставляемый TPL. Не нужно бросать исключения. Это происходит только в том случае, если вы вызываете ThrowIfCancellationRequested. Вы можете использовать IsCancellationRequested вместо этого, чтобы просто проверить состояние маркера отмены.

Вот очень общий шаблон, который вы можете использовать для начала работы.

public class YourService : ServiceBase
{
  private CancellationTokenSource cts = new CancellationTokenSource();
  private Task mainTask = null;

  protected override void OnStart(string[] args)
  {
    mainTask = new Task(Poll, cts.Token, TaskCreationOptions.LongRunning);
    mainTask.Start();
  }

  protected override void OnStop()
  {
    cts.Cancel();
    mainTask.Wait();
  }

  private void Poll()
  {
    CancellationToken cancellation = cts.Token;
    TimeSpan interval = TimeSpan.Zero;
    while (!cancellation.WaitHandle.WaitOne(interval))
    {
      try 
      {
        // Put your code to poll here.
        // Occasionally check the cancellation state.
        if (cancellation.IsCancellationRequested)
        {
          break;
        }
        interval = WaitAfterSuccessInterval;
      }
      catch (Exception caught)
      {
        // Log the exception.
        interval = WaitAfterErrorInterval;
      }
    }
  }
}

Как я уже сказал, я обычно использую выделенный поток/задачу вместо таймера. Я делаю это, потому что мой интервал опроса почти никогда не является постоянным. Обычно я начинаю замедлять опросы, если обнаружена кратковременная ошибка (например, проблемы с доступом к сети или серверу) таким образом, что мой файл журнала не заполняет одно и то же сообщение об ошибке снова и снова с быстрой последовательностью.

Ответ 2

У вас есть несколько вариантов. Чтобы начать с того, что может быть самым простым вариантом, вы можете решить создать приложение в качестве консольного приложения и запустить исполняемый файл в качестве задачи в планировщике задач Windows. Все, что вам нужно сделать, это назначить исполняемый файл, чтобы программа запускалась в задаче, и планировщик задач обрабатывает интервал времени для вас. Вероятно, это предпочтительный вариант, если вы не заботитесь о состоянии и не будете беспокоиться о создании и управлении службой Windows, если вам это действительно не нужно. См. Следующую ссылку о том, как использовать планировщик.

Планировщик задач Windows

Следующий способ, которым вы могли бы это сделать, - создать службу Windows, а в этой службе использовать таймер, в частности System.Timers.Timer. По сути, вы должны установить интервал таймера на количество времени, которое вы хотели бы пройти, прежде чем запускать свой процесс. Затем вы подписываетесь на событие таймера, которое будет срабатывать каждый раз, когда будет происходить этот интервал. В этом случае вы, по сути, будете иметь процесс, который вы хотели бы запустить; это может вызвать дополнительные потоки, если вы хотите. Затем после этой первоначальной настройки вы просто вызовете функцию Timers Start() или установите для свойства Enabled значение True, чтобы запустить таймер. Хороший пример того, как это будет выглядеть, можно найти в примере на странице MSDN, описывающей объект. Существует множество учебных пособий, в которых показано, как настроить службу Windows, поэтому я не буду вникать в это специально.

MSDN: System.Timers.Timer

Наконец, более сложным было бы установить службу Windows, которая прослушивает SqlDependency. Этот метод полезен, если что-то может произойти в базе данных вне вашего приложения, но вы должны быть осведомлены об этом в своем приложении или какой-либо другой службе. Следующая ссылка содержит хорошее руководство по настройке SqlDependency в приложении.

Использование SqlDependency для мониторинга изменений базы данных SQL


Две вещи, которые я хотел бы указать из вашего первоначального сообщения, которые не являются конкретными для вашего вопроса.

  • Если вы пишете настоящую службу Windows, вы не хотите, чтобы служба остановилась. Служба должна работать постоянно, и если возникает исключение, ее следует обрабатывать надлежащим образом и не останавливать службу.

  • Анекдот отмены не должен генерировать исключение; просто не вызывая ThrowIfCancellationRequested() приведет к тому, что исключение не будет выбрано или если это свойство CancellationTokenSource установило аргумент false в методе Cancel, а затем проверит токен, чтобы узнать, запрашивается ли отмена в ваших потоках и изящно возвращается из потока если это так.

Например:

    CancellationTokenSource cts = new CancellationTokenSource();
    ParallelOptions options = new ParallelOptions
    {
        CancellationToken = cts.Token
    };
    Parallel.ForEach(data, options, i =>
    {
        try
        {
            if (cts.IsCancellationRequested) return;

            //do stuff

        }
        catch (Exception ex)
        {
            cts.Cancel(false);
        }
    });