SlideShare a Scribd company logo
1 of 56
Download to read offline
Dennis van der Stelt
all your batch jobs are belong to us
Dennis van der Stelt
Software Architect
http://dennis.bloggingabout.net/
dennis@bloggingabout.net
Particular Software engineer
death of the batch job
@dvdstelt
#nservicebus
Dennis van der Stelt
AGENDA
Dennis van der Stelt
NServiceBus
In Particular
Dennis van der Stelt
NServiceBus
It’s not like WCF, which does RPC
But closes to WCF than to BizTalk
Dennis van der Stelt
BUS TOPOLOGY
Dennis van der Stelt
Messaging
What is it and why do I need it?
reduce
coupling
Dennis van der Stelt
SpatialTemporalPlatform
coupling aspects
Dennis van der Stelt
PLATFORM
Also known as ‘interoperability’
http, json, xml, xsd, etc…
Dennis van der Stelt
TEMPORAL
Store Front End Shipping Service
Dennis van der Stelt
TEMPORAL
Store Front End Shipping ServiceShipping Service
Dennis van der Stelt
TEMPORAL
Store Front End Shipping ServiceOrder Queue
Dennis van der Stelt
TEMPORAL
Store Front End Shipping ServiceOrder Queue
Dennis van der Stelt
TEMPORAL
Store Front End Shipping ServiceOrder Queue
Dennis van der Stelt
Messaging
 Reduces spatial coupling
 XML/JSON for platform coupling
 Asynchronous for temporal coupling
demo
Messaging using WCF
Dennis van der Stelt
PERFORMANCE
RPC versus Messaging
Dennis van der Stelt
NServiceBus Sagas
A pattern by relation database community
Dennis van der Stelt
demo
NServiceBus Sagas
Dennis van der Stelt
Sagas Recap
“What have you done” – Within Temptation
Dennis van der Stelt
HANDLING MESSAGES
Behavior like normal message handlers
class MySaga : IHandleMessages<MyMessage>
{
public void Handle(MyMessage message)
{
…
}
}
Dennis van der Stelt
STARTING SAGAS
Extends the default IHandleMessages<T>
class MySaga : IAmStartedByMessages<MyMessage>
{
public void Handle(MyMessage message)
{
…
}
}
Dennis van der Stelt
STORING STATE
Extends the default IHandleMessages<T>
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>
{
public void Handle(MyMessage message)
{
this.Saga.Data.MyStateProperty = Message.MyProperty;
}
}
Dennis van der Stelt
CORRELATING MESSAGES TO SAGA INSTANCE
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>
{
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MySagaData> mapper)
{
mapper.ConfigureMapping<MyMessage>(m => m.MyProperty).ToSaga(s => s.MyStateProperty);
}
public void Handle(MyMessage message)
{
this.Saga.Data.MyStateProperty = Message.MyProperty;
}
}
Dennis van der Stelt
REQUESTING TIMEOUTS
Reminders to the Saga itself
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>,
IHandleTimeouts<MyTimeout>
{
public void Handle(MyMessage message)
{
this.Saga.Data.MyStateProperty = Message.MyProperty;
RequestTimeout<MyTimeout>(TimeSpan.FromSeconds(10));
}
public void Timeout(MyTimeout state)
{
…
}
}
Dennis van der Stelt
SENDING MESSAGES
Reminders to the Saga itself
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>
{
public void Handle(MyMessage message)
{
this.Saga.Data.MyStateProperty = Message.MyProperty;
this.Bus.Send(new MyCommand());
this.Bus.Publish(new MyEvent());
}
}
Dennis van der Stelt
SAGA STATE
Memento
class MySagaData : IContainSagaData
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
[Unique]
public virtual Guid MySagaId { get; set; }
}
ALTER TABLE [dbo].[MySagaData]
ADD UNIQUE NONCLUSTERED
([MySagaId] ASC) ON [PRIMARY]
Dennis van der Stelt
SAGA STATE
Memento
class MySagaData : IContainSagaData
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
[Unique]
public virtual Guid MySagaId { get; set; }
public virtual IList<Product> Products { get; set; }
}
public class Product
{
public virtual Guid ProductId { get; set; }
}
Dennis van der Stelt
SAGA STATE
Memento
class MySagaData : IContainSagaData
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
[Unique]
public virtual Guid MySagaId { get; set; }
public virtual IList<Product> Products { get; set; }
}
public class Product
{
public virtual Guid ProductId MyUniqueId { get; set; }
}
Dennis van der Stelt
Death to the batch job
Because we don’t want to depend on operations ;-)
Dennis van der Stelt
Dennis van der Stelt
scheduled tasks
Your CEO had insomnia and was using the system in the
middle of the night. The batch job failed somewhere in
the middle of updating 74 million records…
You need to figure out which row it failed on (how?),
why it failed, correct the issue, then start the job again
from where it left off, because if you have to start from
the beginning, it won't get done before peak hours in
the morning.
because that sounds better than batch job
Dennis van der Stelt
BATCH JOB
All customers that ordered $5000 in the last year, get preferred status
DateTime cutoff = DateTime.Today.AddDays(-365);
foreach(var customer in customers)
{
var orderTotal = customer.Orders
.Where(o => o.OrderDate > cutoff)
.Sum(order => order.OrderValue);
customer.Prefered = orderTotal > 5000;
}
Dennis van der Stelt
Tromsø, Norway
Dennis van der Stelt
what if
we can see things before they happen?
Dennis van der Stelt
customer preferred status
Dev: Let's say Steve orders something
for $100. At what point does that
amount no longer count toward Steve's
preferred status?
BA: That's easy, after 365 days!
Dennis van der Stelt
-$300-$100
+$300
DURABLE TIMEOUTS
Our way to predict the future
2015 2016
+$100
Dennis van der Stelt
DURABLE TIMEOUTS
public void Handle(OrderPlaced message)
{
if(this.Data.CustomerId == 0)
this.Data.CustomerId = message.CustomerId;
this.Data.RunningTotal += message.Amount;
this.RequestTimeout<OrderExpired>(TimeSpan.FromDays(365),
timeout => timeout.Amount = message.Amount);
CheckForPreferredStatusChange();
}
public void Handle(OrderExpired message)
{
this.Data.RunningTotal -= message.Amount;
CheckForPreferredStatusChange();
}
Dennis van der Stelt
DURABLE TIMEOUTS
private void CheckForPreferredStatusChange()
{
if(this.Data.PreferredStatus == false && this.Data.RunningTotal >= 5000)
{
this.Bus.Publish<CustomerHasBecomePreferred>(
evt => evt.CustomerId = this.Data.CustomerId);
}
else if(this.Data.PreferredStatus == true && this.Data.RunningTotal < 5000)
{
this.Bus.Publish<CustomerHasBecomeNonPreferred(
evt => evt.CustomerId = this.Data.CustomerId);
}
}
Dennis van der Stelt
Best Practices
The silver bullets?
Dennis van der Stelt
Rule #1 : Don’t query data
Never ever, ever, ever query data
- From the saga to another data source
- Owned by saga with a 3rd party tool
Dennis van der Stelt
Business eventsTimeoutsStarting sagas
out of order
Dennis van der Stelt
ASYNCHRONOUS COMMUNICATION
Order of message delivery
OrderAccepted
OrderAccepted
OrderBilled
Dennis van der Stelt
ASYNCHRONOUS COMMUNICATION
Order of message delivery
OrderAccepted
OrderAccepted
OrderBilled
Dennis van der Stelt
ASYNCHRONOUS COMMUNICATION
Order of message delivery
OrderAccepted
OrderAccepted
OrderBilled
OrderCancelled
How to solve?
race conditions do not exist
Dennis van der Stelt
STARTING SAGAS
What business events can start a Saga?
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>,
IAmStartedByMessages<YourMessage>,
IAmStartedByMessages<AnotherMesssage>
{
public void Handle(MyMessage message)
{
…
if (VerifyState())
MarkAsComplete();
}
}
Dennis van der Stelt
404 ON SAGAS
What if the Saga was already MarkedAsComplete
public class SagaNotFoundHandler : IHandleSagaNotFound
{
IBus bus;
public SagaNotFoundHandler(IBus bus)
{
this.bus = bus;
}
public void Handle(object message)
{
bus.Reply(new SagaDisappearedMessage());
}
}
Dennis van der Stelt
AUTO CORRELATION
Avoids the need for mapping responses
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>,
IHandleMessages<Response>
{
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MySagaData> mapper)
{
mapper.ConfigureMapping<MyMessage>(m => m.MyProperty).ToSaga(s => s.MyStateProperty);
// Mapping for Respose not needed!
}
}
public class RequestHandler : IHandleMessages<Request> {
public void Handle(Request message) {
Bus.Reply(new Response());
}
}
Dennis van der Stelt
AUTO CORRELATION
Avoids the need for mapping responses
class MySaga : Saga<MySagaData>,
IAmStartedByMessages<MyMessage>,
IHandleMessages<MyTimeout>
{
public void Timeout(MyTimeout state)
{
if (state.RasiedAtUtc == …
}
}
public class MyTimeout
{
public DateTime RaisedAtUtc { get; set; } = DateTime.UtcNow;
}
Can be a POCO
No `virtual` as it’s serialized to string format
Dennis van der Stelt
CONCURRENCY
[LockMode(LockModes.Read)]
class ShoppingCartSagaData : IContainSagaData
{
…
[RowVersion]
public virtual int RowVersion { get; set; }
[Unique]
public virtual Guid CartId { get; set; }
}
Dennis van der Stelt
CONCURRENCY
DELETE FROM ShoppingCartSagaData
WHERE Id = '1C669378-3508-4A20-8EFD-A5C60168893E'
AND Originator is null
AND OriginalMessageId = 'd6436b7-eb17-4de5-8b92-a5c60168888c'
AND CartId = '49784AF0-0854-4FF9-B8CD-E57CC8EE6CFC‘
AND …
AND …
AND …
DELETE FROM ShoppingCartSagaData
WHERE Id = '1C669378-3508-4A20-8EFD-A5C60168893E'
AND RowVersion = 1
Sagas is business agility
http://bit.ly/nlnsbug
Dennis van der Stelt
Please…
stay in touch!
http://dennis.bloggingabout.net
dennis@bloggingabout.net

More Related Content

Similar to Death of the batch job - NServiceBus Sagas

Phreebird Suite 1.0: Introducing the Domain Key Infrastructure
Phreebird Suite 1.0:  Introducing the Domain Key InfrastructurePhreebird Suite 1.0:  Introducing the Domain Key Infrastructure
Phreebird Suite 1.0: Introducing the Domain Key InfrastructureDan Kaminsky
 
Beyond php it's not (just) about the code
Beyond php   it's not (just) about the codeBeyond php   it's not (just) about the code
Beyond php it's not (just) about the codeWim Godden
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive? Tomasz Kowalczewski
 
Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeWim Godden
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonPyCon Italia
 
MongoDB World 2014 - BillRun, Billing on top of MongoDB
MongoDB World 2014 - BillRun, Billing on top of MongoDBMongoDB World 2014 - BillRun, Billing on top of MongoDB
MongoDB World 2014 - BillRun, Billing on top of MongoDBOfer Cohen
 
Mongo db world 2014 billrun
Mongo db world 2014   billrunMongo db world 2014   billrun
Mongo db world 2014 billrunMongoDB
 
MVC Design in Web backend Server
MVC Design in Web backend ServerMVC Design in Web backend Server
MVC Design in Web backend ServerChris Wang
 

Similar to Death of the batch job - NServiceBus Sagas (9)

Phreebird Suite 1.0: Introducing the Domain Key Infrastructure
Phreebird Suite 1.0:  Introducing the Domain Key InfrastructurePhreebird Suite 1.0:  Introducing the Domain Key Infrastructure
Phreebird Suite 1.0: Introducing the Domain Key Infrastructure
 
JavaScript Refactoring
JavaScript RefactoringJavaScript Refactoring
JavaScript Refactoring
 
Beyond php it's not (just) about the code
Beyond php   it's not (just) about the codeBeyond php   it's not (just) about the code
Beyond php it's not (just) about the code
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive?
 
Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the code
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con Python
 
MongoDB World 2014 - BillRun, Billing on top of MongoDB
MongoDB World 2014 - BillRun, Billing on top of MongoDBMongoDB World 2014 - BillRun, Billing on top of MongoDB
MongoDB World 2014 - BillRun, Billing on top of MongoDB
 
Mongo db world 2014 billrun
Mongo db world 2014   billrunMongo db world 2014   billrun
Mongo db world 2014 billrun
 
MVC Design in Web backend Server
MVC Design in Web backend ServerMVC Design in Web backend Server
MVC Design in Web backend Server
 

More from Dennis van der Stelt

More from Dennis van der Stelt (10)

Change your architecture during deployment
Change your architecture during deploymentChange your architecture during deployment
Change your architecture during deployment
 
Dealing with eventual consistency
Dealing with eventual consistencyDealing with eventual consistency
Dealing with eventual consistency
 
Dealing with eventual consistency
Dealing with eventual consistencyDealing with eventual consistency
Dealing with eventual consistency
 
Duplicating data or replicating data in Micro Services
Duplicating data or replicating data in Micro ServicesDuplicating data or replicating data in Micro Services
Duplicating data or replicating data in Micro Services
 
Silverlight & WCF RIA
Silverlight & WCF RIASilverlight & WCF RIA
Silverlight & WCF RIA
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
AppFabric Velocity
AppFabric VelocityAppFabric Velocity
AppFabric Velocity
 
Continuous integration
Continuous integrationContinuous integration
Continuous integration
 
App fabric introduction
App fabric introductionApp fabric introduction
App fabric introduction
 
SOLID Principles part 1
SOLID Principles part 1SOLID Principles part 1
SOLID Principles part 1
 

Recently uploaded

My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 

Recently uploaded (20)

My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 

Death of the batch job - NServiceBus Sagas

  • 1. Dennis van der Stelt all your batch jobs are belong to us Dennis van der Stelt Software Architect http://dennis.bloggingabout.net/ dennis@bloggingabout.net Particular Software engineer death of the batch job @dvdstelt #nservicebus
  • 2. Dennis van der Stelt AGENDA
  • 3. Dennis van der Stelt NServiceBus In Particular
  • 4. Dennis van der Stelt NServiceBus It’s not like WCF, which does RPC But closes to WCF than to BizTalk
  • 5. Dennis van der Stelt BUS TOPOLOGY
  • 6. Dennis van der Stelt Messaging What is it and why do I need it?
  • 8. Dennis van der Stelt SpatialTemporalPlatform coupling aspects
  • 9. Dennis van der Stelt PLATFORM Also known as ‘interoperability’ http, json, xml, xsd, etc…
  • 10. Dennis van der Stelt TEMPORAL Store Front End Shipping Service
  • 11. Dennis van der Stelt TEMPORAL Store Front End Shipping ServiceShipping Service
  • 12. Dennis van der Stelt TEMPORAL Store Front End Shipping ServiceOrder Queue
  • 13. Dennis van der Stelt TEMPORAL Store Front End Shipping ServiceOrder Queue
  • 14. Dennis van der Stelt TEMPORAL Store Front End Shipping ServiceOrder Queue
  • 15. Dennis van der Stelt Messaging  Reduces spatial coupling  XML/JSON for platform coupling  Asynchronous for temporal coupling
  • 17. Dennis van der Stelt PERFORMANCE RPC versus Messaging
  • 18. Dennis van der Stelt NServiceBus Sagas A pattern by relation database community
  • 19. Dennis van der Stelt
  • 21. Dennis van der Stelt Sagas Recap “What have you done” – Within Temptation
  • 22. Dennis van der Stelt HANDLING MESSAGES Behavior like normal message handlers class MySaga : IHandleMessages<MyMessage> { public void Handle(MyMessage message) { … } }
  • 23. Dennis van der Stelt STARTING SAGAS Extends the default IHandleMessages<T> class MySaga : IAmStartedByMessages<MyMessage> { public void Handle(MyMessage message) { … } }
  • 24. Dennis van der Stelt STORING STATE Extends the default IHandleMessages<T> class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage> { public void Handle(MyMessage message) { this.Saga.Data.MyStateProperty = Message.MyProperty; } }
  • 25. Dennis van der Stelt CORRELATING MESSAGES TO SAGA INSTANCE class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage> { protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MySagaData> mapper) { mapper.ConfigureMapping<MyMessage>(m => m.MyProperty).ToSaga(s => s.MyStateProperty); } public void Handle(MyMessage message) { this.Saga.Data.MyStateProperty = Message.MyProperty; } }
  • 26. Dennis van der Stelt REQUESTING TIMEOUTS Reminders to the Saga itself class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage>, IHandleTimeouts<MyTimeout> { public void Handle(MyMessage message) { this.Saga.Data.MyStateProperty = Message.MyProperty; RequestTimeout<MyTimeout>(TimeSpan.FromSeconds(10)); } public void Timeout(MyTimeout state) { … } }
  • 27. Dennis van der Stelt SENDING MESSAGES Reminders to the Saga itself class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage> { public void Handle(MyMessage message) { this.Saga.Data.MyStateProperty = Message.MyProperty; this.Bus.Send(new MyCommand()); this.Bus.Publish(new MyEvent()); } }
  • 28. Dennis van der Stelt SAGA STATE Memento class MySagaData : IContainSagaData { public virtual Guid Id { get; set; } public virtual string Originator { get; set; } public virtual string OriginalMessageId { get; set; } [Unique] public virtual Guid MySagaId { get; set; } } ALTER TABLE [dbo].[MySagaData] ADD UNIQUE NONCLUSTERED ([MySagaId] ASC) ON [PRIMARY]
  • 29. Dennis van der Stelt SAGA STATE Memento class MySagaData : IContainSagaData { public virtual Guid Id { get; set; } public virtual string Originator { get; set; } public virtual string OriginalMessageId { get; set; } [Unique] public virtual Guid MySagaId { get; set; } public virtual IList<Product> Products { get; set; } } public class Product { public virtual Guid ProductId { get; set; } }
  • 30. Dennis van der Stelt SAGA STATE Memento class MySagaData : IContainSagaData { public virtual Guid Id { get; set; } public virtual string Originator { get; set; } public virtual string OriginalMessageId { get; set; } [Unique] public virtual Guid MySagaId { get; set; } public virtual IList<Product> Products { get; set; } } public class Product { public virtual Guid ProductId MyUniqueId { get; set; } }
  • 31. Dennis van der Stelt Death to the batch job Because we don’t want to depend on operations ;-)
  • 32. Dennis van der Stelt
  • 33. Dennis van der Stelt scheduled tasks Your CEO had insomnia and was using the system in the middle of the night. The batch job failed somewhere in the middle of updating 74 million records… You need to figure out which row it failed on (how?), why it failed, correct the issue, then start the job again from where it left off, because if you have to start from the beginning, it won't get done before peak hours in the morning. because that sounds better than batch job
  • 34. Dennis van der Stelt BATCH JOB All customers that ordered $5000 in the last year, get preferred status DateTime cutoff = DateTime.Today.AddDays(-365); foreach(var customer in customers) { var orderTotal = customer.Orders .Where(o => o.OrderDate > cutoff) .Sum(order => order.OrderValue); customer.Prefered = orderTotal > 5000; }
  • 35. Dennis van der Stelt Tromsø, Norway
  • 36. Dennis van der Stelt what if we can see things before they happen?
  • 37. Dennis van der Stelt customer preferred status Dev: Let's say Steve orders something for $100. At what point does that amount no longer count toward Steve's preferred status? BA: That's easy, after 365 days!
  • 38. Dennis van der Stelt -$300-$100 +$300 DURABLE TIMEOUTS Our way to predict the future 2015 2016 +$100
  • 39. Dennis van der Stelt DURABLE TIMEOUTS public void Handle(OrderPlaced message) { if(this.Data.CustomerId == 0) this.Data.CustomerId = message.CustomerId; this.Data.RunningTotal += message.Amount; this.RequestTimeout<OrderExpired>(TimeSpan.FromDays(365), timeout => timeout.Amount = message.Amount); CheckForPreferredStatusChange(); } public void Handle(OrderExpired message) { this.Data.RunningTotal -= message.Amount; CheckForPreferredStatusChange(); }
  • 40. Dennis van der Stelt DURABLE TIMEOUTS private void CheckForPreferredStatusChange() { if(this.Data.PreferredStatus == false && this.Data.RunningTotal >= 5000) { this.Bus.Publish<CustomerHasBecomePreferred>( evt => evt.CustomerId = this.Data.CustomerId); } else if(this.Data.PreferredStatus == true && this.Data.RunningTotal < 5000) { this.Bus.Publish<CustomerHasBecomeNonPreferred( evt => evt.CustomerId = this.Data.CustomerId); } }
  • 41. Dennis van der Stelt Best Practices The silver bullets?
  • 42. Dennis van der Stelt Rule #1 : Don’t query data Never ever, ever, ever query data - From the saga to another data source - Owned by saga with a 3rd party tool
  • 43. Dennis van der Stelt Business eventsTimeoutsStarting sagas out of order
  • 44. Dennis van der Stelt ASYNCHRONOUS COMMUNICATION Order of message delivery OrderAccepted OrderAccepted OrderBilled
  • 45. Dennis van der Stelt ASYNCHRONOUS COMMUNICATION Order of message delivery OrderAccepted OrderAccepted OrderBilled
  • 46. Dennis van der Stelt ASYNCHRONOUS COMMUNICATION Order of message delivery OrderAccepted OrderAccepted OrderBilled OrderCancelled How to solve?
  • 47. race conditions do not exist
  • 48. Dennis van der Stelt STARTING SAGAS What business events can start a Saga? class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage>, IAmStartedByMessages<YourMessage>, IAmStartedByMessages<AnotherMesssage> { public void Handle(MyMessage message) { … if (VerifyState()) MarkAsComplete(); } }
  • 49. Dennis van der Stelt 404 ON SAGAS What if the Saga was already MarkedAsComplete public class SagaNotFoundHandler : IHandleSagaNotFound { IBus bus; public SagaNotFoundHandler(IBus bus) { this.bus = bus; } public void Handle(object message) { bus.Reply(new SagaDisappearedMessage()); } }
  • 50. Dennis van der Stelt AUTO CORRELATION Avoids the need for mapping responses class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage>, IHandleMessages<Response> { protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MySagaData> mapper) { mapper.ConfigureMapping<MyMessage>(m => m.MyProperty).ToSaga(s => s.MyStateProperty); // Mapping for Respose not needed! } } public class RequestHandler : IHandleMessages<Request> { public void Handle(Request message) { Bus.Reply(new Response()); } }
  • 51. Dennis van der Stelt AUTO CORRELATION Avoids the need for mapping responses class MySaga : Saga<MySagaData>, IAmStartedByMessages<MyMessage>, IHandleMessages<MyTimeout> { public void Timeout(MyTimeout state) { if (state.RasiedAtUtc == … } } public class MyTimeout { public DateTime RaisedAtUtc { get; set; } = DateTime.UtcNow; } Can be a POCO No `virtual` as it’s serialized to string format
  • 52. Dennis van der Stelt CONCURRENCY [LockMode(LockModes.Read)] class ShoppingCartSagaData : IContainSagaData { … [RowVersion] public virtual int RowVersion { get; set; } [Unique] public virtual Guid CartId { get; set; } }
  • 53. Dennis van der Stelt CONCURRENCY DELETE FROM ShoppingCartSagaData WHERE Id = '1C669378-3508-4A20-8EFD-A5C60168893E' AND Originator is null AND OriginalMessageId = 'd6436b7-eb17-4de5-8b92-a5c60168888c' AND CartId = '49784AF0-0854-4FF9-B8CD-E57CC8EE6CFC‘ AND … AND … AND … DELETE FROM ShoppingCartSagaData WHERE Id = '1C669378-3508-4A20-8EFD-A5C60168893E' AND RowVersion = 1
  • 54. Sagas is business agility
  • 56. Dennis van der Stelt Please… stay in touch! http://dennis.bloggingabout.net dennis@bloggingabout.net