我一直在使用ServiceStack MQ服务器/客户端来支持我平台中基于消息的架构,并且它一直运行良好。我现在正在尝试做一些我认为SS Message Producer / Consumer不支持的事情。
基本上我是在集中式数据中心解雇消息(事件)而我在美国各地有大约2000个分散节点,这些节点需要潜在地了解这个事件,但这个事件需要针对的是只有~2000个节点中的一个。我需要具有Pub / Sub的任意命名通道的灵活性,但需要MQ的持久性。我从Pub / Sub开始,但网络太不可靠,所以我已经移动了解决方案以使用RedisMQServer。我有它工作,但想确保我没有错过界面中的东西。我很好奇SS的创作者是否已经考虑过这个用例,如果是这样的话,讨论的结果是什么?这确实与使用POCO驱动消息消费的结果/动作的概念作斗争。也许这就是原因?
这是我的制片人
public ExpressLightServiceResponse Get(ExpressLightServiceRequest query)
{
var result = new ExpressLightServiceResponse();
var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("ArbitaryNamespace"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
var typeBuilder = moduleBuilder.DefineType(string.Format("EventA{0}", query.Store), TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
var newType = typeBuilder.CreateType();
using (var messageProducer = _messageService.CreateMessageProducer())
{
var message = MessageFactory.Create(newType.CreateInstance());
messageProducer.Publish(message);
}
return result;
}
这是我的消费者
public class ServerAppHost : AppHostHttpListenerBase
{
private readonly string _store;
public string StoreQueue => $"EventA{_store}";
public ServerAppHost(string store) : base("Express Light Server", typeof(PubSubServiceStatsService).Assembly)
{
_store = store;
}
public override void Configure(Container container)
{
container.Register<IRedisClientsManager>(new PooledRedisClientManager(ConfigurationManager.ConnectionStrings["Redis"].ConnectionString));
var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("ArbitaryNamespace"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
var typeBuilder = moduleBuilder.DefineType(StoreQueue, TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
var newType = typeBuilder.CreateType();
var mi = typeof(Temp).GetMethod("Foo");
var fooRef = mi.MakeGenericMethod(newType);
fooRef.Invoke(new Temp(container.Resolve<IRedisClientsManager>()), null);
}
}
public class Temp
{
private readonly IRedisClientsManager _redisClientsManager;
public Temp(IRedisClientsManager redisClientsManager)
{
_redisClientsManager = redisClientsManager;
}
public void Foo<T>()
{
var mqService = new RedisMqServer(_redisClientsManager);
mqService.RegisterHandler<T>(DoWork);
mqService.Start();
}
private object DoWork<T>(IMessage<T> arg)
{
//Do work
return null;
}
}
这给了我的是Pub / Sub的灵活性和队列的持久性。有没有人看到/知道更多&#34;本地人&#34;实现这个目标的方法?
答案 0 :(得分:0)
在你的AppHost中只应该注册1个MQ主机,所以我首先将它从你的包装类中删除,并让它只注册处理程序,例如:
public override void Configure(Container container)
{
//...
container.Register<IMessageService>(
c => new RedisMqServer(c.Resolve<IRedisClientsManager>());
var mqServer = container.Resolve<IMessageService>();
fooRef.Invoke(new Temp(mqServer), null);
mqServer.Start();
}
public class Temp
{
private readonly IMessageService mqServer;
public Temp(IMessageService mqServer)
{
this.mqServer = mqServer;
}
public void Foo<T>() => mqService.RegisterHandler<T>(DoWork);
}
但是这种方法不适合ServiceStack,它鼓励使用代码优先的消息,它定义客户端/服务器用来处理发送和接收的消息的服务合同。因此,如果您想使用ServiceStack发送自定义消息,我建议每个消息都有一个单独的类,否则有一个类似SendEvent
的泛型类型,其中消息或事件类型是该类的属性。
否则,如果您想继续使用自定义消息,请不要使用RedisMqServer
,您可以使用dedicated MQ like Rabbit MQ,或者如果您更喜欢使用Redis List directly - 这是数据结构所有Redis MQ都在下面使用。