如何在C#服务中进行多个发布调度?

时间:2011-09-22 19:05:06

标签: c# multithreading wcf service scheduling

我有一项服务正在监听来自上游系统的位置更新。现在这个职位更新有多个消费者。

  • 一位消费者希望尽快获得更新
  • 一位消费者希望每30秒更新一次
  • 一位消费者希望在累积50次更新时获得更新
  • 一位消费者希望在累积50次更新或30秒后获得更新。

以上可以随时更改,还是可以添加新的变体?

如何实现这种可配置,可扩展以及我应该采用何种编程方法。

我正在开发C#,Window Service

1 个答案:

答案 0 :(得分:0)

听起来您正在描述一种情况,即服务是发布源(服务本身是订阅者)之间的中介,服务将此信息重新广播给 N 订阅者,但是根据他们的日程安排。

因此,假设更新是单个位置更新,而不是某种聚合,如滚动平均值或缓冲(例如,每30秒一次汽车的最新位置,而不是自最近30秒以来的所有位置),那么你需要为每个用户保留一些信息:

  • 订阅。谁是消费者?我该如何通知? (例如回叫,回复队列等)
  • 规范。消费者想要什么,什么时候需要? (例如,每50个蜱)
  • 状态
    • 自上次发送以来的时间
    • 自上次发送以来的更新次数
    • ...

当服务接收更新时,对于每个使用者,它必须针对来自源的每次更新的状态评估规范;类似的东西:

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

以上假设您的规范可由服务直接执行(即,消费者正在进行中或规范已序列化并且可以由服务反序列化。如果此不是的话,你的规范可能代表一个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),线程池线程或长期存在的线程将如上所述出列并评估更新。这有很多可能的变化和优化。