Einführung in NServiceBus 2. Kassel .NET Usergroup - 23.02.2017 Alexander Bremora
Wer kennt NServiceBus? ? 23.02.2017
Code zu schreiben ist … EINFACH … solange 23.02.2017
… solange man weiß, … was einen erwartet 23.02.2017
Aber was tun, wenn … … bestimmte Aspekte nicht vorauszusehen sind? 23.02.2017
Denn nur, weil … Deine Software extrem schnell auf Deiner Maschine läuft Deine lokale Datenbank noch niemals einen Timeout verursacht hat Dein Netzwerk immer zu 100% performt Deine WebServices 24/7 erreichbar sind … geht trotzdem mal was schief 23.02.2017
Ein Bus Framework hilft beim … Design von Event-Driven Systemen (Event Sourcing, CQRS) Entkoppeln von Zuständigkeiten & Ressourcen (SRP) Automatische Fehlerbehandlung (Retry) Abstahiert Queues RPC Wrapper Single Responsibility Principle Datenbank E-Mail Services LASTVERARBEITUNG (threading, cloud handlers) Sheduling 23.02.2017
Was brauche ich dafür? Das Framework NServiceBus Transport Technologien ( Queues vs. Broker) DB Persistenz (z.B. für Subscriber) 23.02.2017
Wie fange ich an? NuGet NServiceBus NuGet NServiceBus.Host Nachricht definieren Konfiguration einrichten (Typen, Ziel, …) Nachricht senden/publishen Nachricht handeln 23.02.2017
Host yourself Du kannst dein Endpoint selber hosten oder Du kannst NServiceBus.Host nutzen NServiceBus.Host nutzt Topshelf unter der Haube NServiceBus.Host führt Deinen Host als Windows Service oder Konsolenapplikation aus Startup & Cleanup 23.02.2017
Unterschiede zu v5 zu v6 Minimum .NET 4.5.2 (empfohlen > 4.6.1) Alle Transportoperation sind async IEndpointInstance (erbt von IMessageSession) ersetzt IBus EndpointConfiguration ersetzt BusConfiguration IHandleMessage Signatur hat sich geändert Task Handle(T message, IMessageHandlerContext context) Methodennamen wurden größtenteils beibehalten V6 seit Oktober 2016 NServiceBus v5 Minium .NET 4.5 Migrationsanleitung ist online EndpointConfiguration(Endpointname) Ibus hat viele Properties und Methoden die nicht in allen Szenarien anwendbar sind (und eine Exception schmeißen) Mit Handle() ist ein Injecten von Ibus nicht mehr erforderlich Kein async suffix: Noise, Kompatibilität Doppelte Peformance message/sec for noop 23.02.2017
Unterschiede zu v5 zu v6 TransportConfig ist obsolet. Nur über Code oder eigene ConfigClass IWantToRunWhenBusStartsAndStops -> IWantToRunWhenEndpointStartsAndStops Kleinvieh: Namespaces umgezogen, Namesänderungen, API Änderungen, Correleated Properties für Saga, Deprecated Serializer, Sender-Side Distrubution ersetzt Distributor Pattern (MSMQ) v5 Support: Bis 24. September 2017 Migrationsanleitung ist online First Level Retries (FLR) has been renamed to Immediate Retries. Second Level Retries (SLR) have been renamed to Delayed Retries. 23.02.2017
Magie Assembly scanning für Tasks Typen / Handler Interfaces IConfigureThisEndpoint IWantToRunWhenEndpointStartsAndStops AutoSubscription Tasks endpointConfiguration.LimitMessageProcessingConcurrencyTo(1); While we default to max(2, NumberOfLogicalProcessors) concurrent messages, you can configure the value to whatever you like: 23.02.2017
Message Handling public class Handler : IHandleMessages<OrderBeerCommand> { public Task Handle(OrderBeerCommand message, IMessageHandlerContext context) { Console.WriteLine($"Beer order received. Amount: {message.Amount}"); return Task.CompletedTask; // return Task.FromResult(0); // for < .NET 4.6 // return null; // Never do this! This will result in an Exception } Handlers sind stateless! Nutze Sagas, wenn Du einen State brauchst. IMessageSession außerhalb, IMessageHandlerContext innerhalb von Handlers nutzen 23.02.2017
DEMO Client OrderBeerCommand Server Replay static async Task<IEndpointInstance> CreateEndpoint() { var endpointName = "KasselDotNet.NServiceBus.BeerPup.Client"; Console.Title = endpointName; var endpointConfiguration = new EndpointConfiguration( endpointName: endpointName); endpointConfiguration.AuditProcessedMessagesTo("audit"); endpointConfiguration.SendFailedMessagesTo("error"); endpointConfiguration.UseSerialization<JsonSerializer>(); endpointConfiguration.EnableInstallers(); endpointConfiguration.UsePersistence<InMemoryPersistence>(); return await Endpoint.Start(endpointConfiguration) .ConfigureAwait(false); } 23.02.2017
Konfiguration - Code public class EndpointConfig : IConfigureThisEndpoint { public void Customize(EndpointConfiguration endpointConfiguration) { endpointConfiguration.UsePersistence<InMemoryPersistence>(); endpointConfiguration.UseSerialization<JsonSerializer>(); // default endpointConfiguration.UseTransport<MsmqTransport>(); // default endpointConfiguration.SendFailedMessagesTo("error"); endpointConfiguration.AuditProcessedMessagesTo("audit"); // Change default directory for logging. Only via code :-( //var defaultFactory = LogManager.Use<DefaultFactory>(); //defaultFactory.Directory("pathToLoggingDirectory"); var recoverability = endpointConfiguration.Recoverability(); recoverability.Immediate( immediate => { immediate.NumberOfRetries(3); }); recoverability.Delayed( delayed => { delayed.NumberOfRetries(3).TimeIncrease(TimeSpan.FromSeconds(2)); }} Error Queue: Für alle Nachrichten, die wiederholt fehlschlagen Audit Queue: Für alle erfolgreich verarbeiteten Nachrichten 23.02.2017
Konfiguration – app.config <configSections> <section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" /> <section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core" /> <section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" /> </configSections> <MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/> <AuditConfig QueueName="audit"/> <UnicastBusConfig> <MessageEndpointMappings> <add Assembly="KasselDotNet.NServiceBus.Core" Type="KasselDotNet.NServiceBus.Core.OrderBeerCommand" Endpoint="KasselDotNet.NServiceBus.BeerPub.Server" /> </MessageEndpointMappings> </UnicastBusConfig> 23.02.2017
Bus (Broker) Technology MSMQ RabbitMQ Azure Service Bus Azure Store Queues SQL Server Legacy: WebSphereMQ 23.02.2017
Persistenz InMemory RavenDB NHibernate Azure Storage SQL Persistence Community Solutions Entity Framework MongoDB PostgreSQL https://docs.particular.net/nservicebus/persistence/ In-Memory A volatile RAM based storage mainly used for development purposes. Can also be used where the storage is not required to persist between process restarts. RavenDB Uses the RavenDB document database for storage. NHibernate Uses custom NHibernate to persist data to an ADO.net data store (e.g. SQL Server). MSMQ A subscription only storage on top of MSMQ. Azure Storage Uses Azure Tables Storage for storage SQL Persistence Uses Json.NET to serialize data and store in a SQL database. 23.02.2017
Event vs. Command Commands ist als Arbeitsauftrag für einen Empfänger vorgesehen Sender & Receiver Nutze ICommand als Markerinterface Call IMessageSession.Send(); Events ist als Benachrichtigung für mehrere Empfänger bestimmt Publisher & Subscriber Nutze IEvent als Markerinterface Call IMessageSession.Publish(); Reply erben von Basisinterface IMessage 23.02.2017
Dependency Injection Built-in DI Support für: Autofac CastleWindsor endpointConfiguration.RegisterComponents( registration: configureComponents => { configureComponents.ConfigureComponent<PromotionService>(DependencyLifecycle.SingleInstance); }); Support für: Autofac CastleWindsor Ninject SimpleInjector Spring StructureMap Unity 23.02.2017
Unobtrusive Mode Messages können über Konventionen „gekennzeichnet“ werden Markerinterface IMessage, ICommand, IEvent entfallen Keine Abhängigkeit zu NServiceBus mehr erforderlich 23.02.2017
DEMO Events registrieren Dependency Injection Client OrderBeerCommand Server PickUpYourBeerCommand BeerWasDrunkEvent GuestDisplay Events registrieren Dependency Injection 23.02.2017
Outbox 1 Seit NServiceBus v5 Dient als Ersatz für Distrubuted Transaction Coordinator (DTC) Verwaltet unterschiedliche Transaktionen Verfügbar für NHibernate & RavenDB Outbox DB == Business Data DB Beispiel: Entität + Event mit Entität-ID DTC ist ein Service von Microsoft ressourcenübergreifend Transaktionen abbilden zu können (Beispiel MSQM und SqlServer) Besonders für Cloud, RabbitMQ (Default) 23.02.2017
Outbox 2 Deduplication Process (Dedup) Filtert bereits verarbeiterte Nachrichten heraus Speicherung MessageIDs + Business Data + Outgoing Messages Mehrfache Outgoing Messages möglich Werden von Dedup als identische Nachrichten erkannt ACHTUNG: Vermischung von DTC & Outbox innerhalb eines System kann zu Datenduplikation führen. DTC Endpoint muss zwingend idempotent sein! 23.02.2017
http://geek-and-poke.com/geekandpoke/2016/1/10/idempotent-and-non-idempotent 23.02.2017
Outbox 3 endpointConfiguration.EnableOutbox(); endpointConfiguration.SetTimeToKeepDeduplicationData(TimeSpan.FromDays(7)); endpointConfiguration.SetFrequencyToRunDeduplicationDataCleanup(TimeSpan.FromMinutes(1)); Für Transport mit Unterstützung für DTC (MSMQ, SqlServer) muss zusätzlich folgende Config gesetzt werden: <appSettings> <add key="NServiceBus/Outbox" value="true" /> </appSettings> 23.02.2017
Unit Of Work public class MyUnitOfWork : IManageUnitsOfWork { public Task Begin() { Console.WriteLine("-- MyUnitOfWork Start --"); return Task.CompletedTask; } public Task End(Exception ex = null) { Console.WriteLine("-- MyUnitOfWork End --"); endpointConfiguration.RegisterComponents( registration: components => { components.ConfigureComponent<MyUnitOfWork>(DependencyLifecycle.InstancePerCall); }); 23.02.2017
Particular Service Platform ServiceControl (the brain) ServiceInsight ServicePulse 23.02.2017
Service Control Zentraler Dienst der Information zu jeder Nachricht sammelt Nutzt audit & error Queue Nutzt Embedded RavenDB Schlecht dokumentierte API unter http://localhost:33333/api Audit messages werden nach 30 Tagen gelöscht Error messages bleiben bestehen Eigene aktive Benachrichtung: Handle ServiceControl.Contracts.MessageFailed event 23.02.2017
Service Insight Applikation, um alle Nachrichtenflüsse zu visualisieren Nachrichten filtern Fehlgeschlagene Nachrichten erneut verarbeiten Nutzt, die REST-API von ServiceControl Für Saga Nuget Pascket installieren 23.02.2017
ServicePulse WebApplikation, die uns Zahlen und Werte zum System anzeigt Gruppiert fehlerhafte Nachrichten Zeigt die Aktivität von Endpoints auf (Heartbeat Nuget) Bietet die Möglichkeit Nachrichten erneut auszuführen Externe Überwachung durch Custom Checks http://localhost:9090 Nutzt REST-API von ServiceControl 23.02.2017
DEMO Unit Of Work Service Control Service Insight Client OrderBeerCommand Server PickUpYourBeerCommand BeerWasDrunkEvent GuestDisplay Unit Of Work Service Control Service Insight 23.02.2017
Tips Nutze Commands, wenn Du sichergehen willst, dass Deine Nachrichten ankommen Idemotenz! Idemotenz! Idemotenz! PerformanceCounter Logging anpassen Möglichst keine großen Datenmengen Async/await Stolpersteine vermeiden Fachliche Fehler müssen gehandelt werden Fehler werden in ServiceControl DB gespeichert. Clonen von Umgebungen schwierig Trenne Audit Refactoring (Rename, Namespace) machen Retries (fast) unmöglich await ConfigureAwait(false) Immer task return 23.02.2017
Lizenz / Kosten Lizenztypen: SaaS Royality-free Elastic Cloud Internal use Startups 23.02.2017
23.02.2017
Monitoring 23.02.2017
Quellen https://support.nservicebus.com/blog/msmq-performance- improvements-in-nservicebus-6.0 https://docs.particular.net/ 23.02.2017
Lust auf mehr? Ein paar Stichwörter: NServiceBus Pipeline Security MessageMutors Message Headers Outbox Sagas Sheduling Security Test Sender-Side Distrubution 23.02.2017
Die letzte Seite Alexander Bremora E-Mail: alex at bremora . com Twitter: @mystackoverflow GitHub: https://github.com/mystackoverflow 23.02.2017