Как сделать планирование нескольких публикаций в сервисе C #? - PullRequest
1 голос
/ 22 сентября 2011

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

  • Один потребитель хочет получить обновление как можно скорее
  • Один потребитель хочет получать обновления каждые 30 секунд
  • Один потребитель хочет получить обновление, когда накоплено 50 обновлений
  • Один потребитель хочет получить обновление, когда накоплено 50 обновлений или 30 секунд, которые когда-либо раньше.

Выше можно изменить в любое время или добавить новый вариант?

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

Я занимаюсь разработкой на C #, Window Service

1 Ответ

0 голосов
/ 10 октября 2011

Похоже, что вы описываете сценарий, в котором служба является посредником между источником публикации (сама служба является подписчиком), и служба повторно передает эту информацию N подписчикам, но в соответствии с их расписание.

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

  • a подписка . Кто такой потребитель? как я могу уведомить об этом? (например, обратный вызов, очередь ответов и т. д.)
  • a спецификация . Чего хочет потребитель и когда? (например, каждые 50 тиков)
  • состояние
    • время с момента последней отправки
    • количество обновлений с момента последней отправки
    • ...

Поскольку служба получает обновления, для каждого потребителя она должна сравнивать спецификацию с состоянием для каждого обновления из источника; что-то вроде:

if (consumer.Spec.Matches(consumer.State, updateMessage)
    SendUpdate(consumer.Subscription.Callback, updateMessage)

Вышеприведенное предполагает, что ваша спецификация непосредственно выполняется службой (т. Е. Потребители находятся в процессе или спецификация была сериализована и может быть десериализована службой. Если это не , то ваша Возможно, spec может представлять DSL (например, разбираемое представление о том, что сервер может быть скомпилирован во что-то, что он может выполнить). Другой подход заключается в представлении спецификации как набора команд. Например,

public enum FrequencyUnit
{
    SecondsSinceLastSend,
    UpdatesSinceLastSend,
}

public class Frequency
{
    public double Value { get; set; }
    public FrequencyUnit Unit { get; set; }
}

public class Operator
{
   Every, // Unary: e.g. every update; every 10 sec; every 5 updates
   Or,   // Nary: e.g. every 50 or every 20 sec (whichever's first)
   And,   // Nary: e.g. 19 messages and 20 sec have passed
   // etc.
}

public class UpdateSpec
{
    public Frequency[] Frequencies { get; set; }
    public Operator Operator  { get; set; }
}

Они довольно гибкие и могут быть настроены на внутреннем коде сервера или встроены чтением XML или чего-то еще. Они также могут быть переданы в службу от самого потребителя при регистрации. Например, IService.Register() может предоставить интерфейс с подпиской и спецификацией.

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

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

...