2016-11-09 2 views
1

Ich habe den ServiceStack MQ Server/Client verwendet, um eine nachrichtenbasierte Architektur in meiner Plattform zu ermöglichen, und es hat einwandfrei funktioniert. Ich versuche jetzt etwas zu tun, von dem ich nicht glaube, dass es vom SS Message Producer/Consumer unterstützt wird.ServiceStack Message Filtering

Im Wesentlichen falle ich Nachrichten (Ereignisse) in einem zentralen Rechenzentrum und ich habe ~ 2000 dezentralisierte Knoten in den gesamten USA über ein nicht zuverlässiges Netzwerk, das möglicherweise über dieses Ereignis wissen müssen, aber das Ereignis muss gezielt werden zu nur einem der ~ 2000 Knoten. Ich brauche die Flexibilität der beliebig benannten Kanäle mit Pub/Sub aber die Haltbarkeit des MQ. Ich habe mit Pub/Sub angefangen, aber das Netzwerk ist zu unzuverlässig, deshalb habe ich die Lösung verschoben, um den RedisMQServer zu verwenden. Ich habe es funktioniert aber wollte sicherstellen, dass ich etwas in der Schnittstelle nicht vermisse. Ich bin neugierig, ob die Schöpfer von SS diesen Anwendungsfall durchdacht haben, und wenn ja, wie war das Ergebnis dieser Diskussion? Dies bekämpft das Konzept der Verwendung der POCOs, um die Ergebnisse/Aktionen des Nachrichtenverbrauchs zu steuern. Vielleicht ist das der Grund?

Hier ist mein Produzent

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; 
    } 

Hier mein Verbraucher

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; 
    } 
} 

Was gibt mir die Flexibilität der Pub/Sub mit der Haltbarkeit einer Queue. Wer kennt/kennt einen eher "nativen" Weg dies zu erreichen?

Antwort

0

Es sollte nur 1 MQ-Host in Ihrem AppHost registriert sein, so würde ich erstens es Klasse aus Ihrem Wrapper entfernen und habe es nur die Handler registrieren, zB:

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); 
} 

Aber dieser Ansatz ist nicht Gut geeignet für ServiceStack, das die Verwendung von Code-First-Nachrichten fördert, die den Servicevertrag definieren, den Client/Server zur Verarbeitung der gesendeten und empfangenen Nachrichten verwenden. Wenn Sie ServiceStack zum Senden von benutzerdefinierten Nachrichten verwenden möchten, sollten Sie entweder eine separate Klasse pro Nachricht verwenden oder einen generischen Typ wie SendEvent, in dem die Nachricht oder der Ereignistyp eine Eigenschaft der Klasse ist.

Andernfalls, wenn Sie den Vorgang fortsetzen möchten mit benutzerdefinierten Nachrichten RedisMqServer nicht verwenden, können Sie nur ein dedicated MQ like Rabbit MQ verwenden oder wenn Sie es vorziehen, verwenden ein Redis List directly - was die Datenstruktur ist, dass alle unter Verwendung des Redis MQ.