embracing nservicebus best practices
DESCRIPTION
Mapping Sages to logical Properties with NservicebusTRANSCRIPT
~
~
Roy CornelissenSoftware Architect
@roycornelissen
Mark TalingLead Developer
@marktaling
Where we started
Discovering NServiceBus
Multi tenancy
Saga’s
The evolution of NServiceBus
Performance considerations
Maintainability
NServiceBus in a brownfield
Wrap up
Q&A
Inte
grat
ion
La
yer
Serv
ice
Laye
r
NIS
Pre
sen
tati
on
La
yer
Planning UI Reporting UI
customer external apps
Employee Self Service
Common Forecast Realization PaymentSchedule
Monitoring & Control
Inte
grat
ion
La
yer
Serv
ice
Laye
r
NIS
Pre
sen
tati
on
La
yer
Planning UI Reporting UIEmployee Self
Service
Common Forecast PaymentSchedule
Service Bus
Integration Services
IS HRM
IS Payroll
IS Budget
IS Provisioning
IS Time
IS Point of Sale
Realization
Tenant ID
Tenant ID
Tenant ID
Tenant ID
public class BuildPrincipalFromHeaders : IMutateIncomingMessages{
public object MutateIncoming(object message){
Thread.CurrentPrincipal = null;
string tenantId = Headers.GetMessageHeader(message, “urn:dv:tenantid”);
ICollection<Claim> claims = new List<Claim>();…claims.Add(new Claim(SecurityConstants.TenantIdClaim, tenantId));
var principal = new ClaimsPrincipal(new ClaimsIdentityCollection { new ClaimsIdentity(claims) });
Thread.CurrentPrincipal = principal;
return message;}
…
public class SetHeadersFromPrincipal : IMutateOutgoingMessages{
public IBus Bus { get; set; }
public object MutateOutgoing(object message){
IClaimsIdentity identity =Thread.CurrentPrincipal.Identity as IClaimsIdentity;
string tenantId = identity.GetTenantId();
if (!string.IsNullOrWhiteSpace(tenantId)){
Bus.SetMessageHeader(message, “urn:dv:tenantid”, tenantId);}
return message;}
…
- Multiple properties- Concatenation- IFindSaga
- ISagaPersister
public class AdvancedRavenSagaPersister : RavenSagaPersister, ISagaPersister{
public AdvancedRavenSagaPersister(RavenSessionFactory sessionFactory):base(sessionFactory)
{
}
public new void Save(IContainSagaData saga){base.Save(saga);
}
public new void Complete(IContainSagaData saga){
base.Complete(saga);}
void ISagaPersister.Save(IContainSagaData saga) { Save(saga); }
void ISagaPersister.Complete(IContainSagaData saga) { Complete(saga); }}
public class AdvancedRavenSagaPersister : RavenSagaPersister, ISagaPersister{
public AdvancedRavenSagaPersister(RavenSessionFactory sessionFactory):base(sessionFactory)
{
}
public new void Save(IContainSagaData saga){base.Save(saga);
}
public new void Complete(IContainSagaData saga){
base.Complete(saga);}
void ISagaPersister.Save(IContainSagaData saga) { Save(saga); }
void ISagaPersister.Complete(IContainSagaData saga) { Complete(saga); }}
public class AdvancedRavenSagaPersister : RavenSagaPersister, ISagaPersister{
public AdvancedRavenSagaPersister(RavenSessionFactory sessionFactory):base(sessionFactory)
{
}
public new void Save(IContainSagaData saga){base.Save(saga);StoreMappingKeys(saga);
}
public new void Complete(IContainSagaData saga){RemoveMappingKeys(saga);base.Complete(saga);
}
void ISagaPersister.Save(IContainSagaData saga) { Save(saga); }
void ISagaPersister.Complete(IContainSagaData saga) { Complete(saga); }}
public class AdvancedRavenSagaPersister : RavenSagaPersister, ISagaPersister{private readonly RavenSessionFactory _sessionFactory;
public AdvancedRavenSagaPersister(RavenSessionFactory sessionFactory):base(sessionFactory)
{_sessionFactory = sessionFactory;
}
public new void Save(IContainSagaData saga){base.Save(saga);StoreMappingKeys(saga);
}
public new void Complete(IContainSagaData saga){RemoveMappingKeys(saga);base.Complete(saga);
}
void ISagaPersister.Save(IContainSagaData saga) { Save(saga); }
void ISagaPersister.Complete(IContainSagaData saga) { Complete(saga); }}
public class AdvancedRavenSagaPersister : RavenSagaPersister, ISagaPersister{private readonly RavenSessionFactory _sessionFactory;
public AdvancedRavenSagaPersister(RavenSessionFactory sessionFactory):base(sessionFactory)
{_sessionFactory = sessionFactory;
}
public new void Save(IContainSagaData saga){base.Save(saga);StoreMappingKeys(saga);
}
public new void Complete(IContainSagaData saga){RemoveMappingKeys(saga);base.Complete(saga);
}
void ISagaPersister.Save(IContainSagaData saga) { Save(saga); }
void ISagaPersister.Complete(IContainSagaData saga) { Complete(saga); }}
var document = _sessionFactory.Session.Include("SagaDocId").Load<SagaMappingIdentity>(mappingId);return _sessionFactory.Session.Load<TSagaData>(document.SagaId);
RequestUtcTimeout<PolicyRenewal>(TimeSpan.FromDays(300));
Lessons learned- Upgrade regularly- Retry PoCs and assumptions- Beware of abstractions
Lessons learned- Upgrade regularly- Retry PoCs and assumptions- Beware of abstractions
Keep yourtransactions on a diet
Design withparallelism in mind
{Tx}[Unique] saga
properties
Keep yourtransactions on a diet
Design withparallelism in mind
{Tx}{Tx}
[Unique] saga properties
{Tx}
UseTransport<Rfc1149>();
http://www.make-awesome.com/2014/04/nservicebus-transport-for-rfc-1149/
NServiceBus is an opinionated framework
If it fits, it fits like a glove
Prepare to make concessions at first
Clean up later
Messaging makes totally different use cases possible
Requires a new mindset for everyone
NServiceBus is a great
way to break open
existing architectures
Despite its flexibility and
pluggability, always follow
its design principles
Go with the flow, it solves
real life problems you
might not know you have
~
Roy CornelissenSoftware Architect
@roycornelissen
Mark TalingLead Developer
@marktaling
blogs.infosupport.com