我有一项服务正在监听来自上游系统的位置更新。现在这个职位更新有多个消费者。
以上可以随时更改,还是可以添加新的变体?
如何实现这种可配置,可扩展以及我应该采用何种编程方法。
我正在开发C#,Window Service
答案 0 :(得分:0)
听起来您正在描述一种情况,即服务是发布源(服务本身是订阅者)之间的中介,服务将此信息重新广播给 N 订阅者,但是根据他们的日程安排。
因此,假设更新是单个位置更新,而不是某种聚合,如滚动平均值或缓冲(例如,每30秒一次汽车的最新位置,而不是自最近30秒以来的所有位置),那么你需要为每个用户保留一些信息:
当服务接收更新时,对于每个使用者,它必须针对来自源的每次更新的状态评估规范;类似的东西:
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),线程池线程或长期存在的线程将如上所述出列并评估更新。这有很多可能的变化和优化。