+ All Categories
Home > Technology > Death of the batch job - NServiceBus Sagas

Death of the batch job - NServiceBus Sagas

Date post: 22-Jan-2018
Category:
Upload: dennis-van-der-stelt
View: 701 times
Download: 4 times
Share this document with a friend
56
Dennis van der Stelt all your batch jobs are belong to us Dennis van der Stelt Software Architect http://dennis.bloggingabout.net/ [email protected] Particular Software engineer death of the batch job @dvdstelt #nservicebus
Transcript
Page 1: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

all your batch jobs are belong to us

Dennis van der Stelt

Software Architect

http://dennis.bloggingabout.net/

[email protected]

Particular Software engineer

death of the batch job

@dvdstelt

#nservicebus

Page 2: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

AGENDA

Page 3: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

NServiceBusIn Particular

Page 4: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

NServiceBus

It’s not like WCF, which does RPC

But closes to WCF than to BizTalk

Page 5: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

BUS TOPOLOGY

Page 6: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

MessagingWhat is it and why do I need it?

Page 7: Death of the batch job - NServiceBus Sagas

reduce

coupling

Page 8: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

SpatialTemporalPlatform

coupling aspects

Page 9: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

PLATFORM

Also known as ‘interoperability’

http, json, xml, xsd, etc…

Page 10: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

TEMPORAL

Store Front End Shipping Service

Page 11: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

TEMPORAL

Store Front End Shipping ServiceShipping Service

Page 12: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

TEMPORAL

Store Front End Shipping ServiceOrder Queue

Page 13: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

TEMPORAL

Store Front End Shipping ServiceOrder Queue

Page 14: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

TEMPORAL

Store Front End Shipping ServiceOrder Queue

Page 15: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Messaging

Reduces spatial coupling

XML/JSON for platform coupling

Asynchronous for temporal coupling

Page 16: Death of the batch job - NServiceBus Sagas

demo

Messaging using WCF

Page 17: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

PERFORMANCE

RPC versus Messaging

Page 18: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

NServiceBus SagasA pattern by relation database community

Page 19: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Page 20: Death of the batch job - NServiceBus Sagas

demo

NServiceBus Sagas

Page 21: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Sagas Recap“What have you done” – Within Temptation

Page 22: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

HANDLING MESSAGES

Behavior like normal message handlers

class MySaga : IHandleMessages<MyMessage>{public void Handle(MyMessage message){…

}}

Page 23: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

STARTING SAGAS

Extends the default IHandleMessages<T>

class MySaga : IAmStartedByMessages<MyMessage>{public void Handle(MyMessage message){…

}}

Page 24: Death of the batch job - NServiceBus Sagas

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;

}}

Page 25: Death of the batch job - NServiceBus Sagas

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;

}}

Page 26: Death of the batch job - NServiceBus Sagas

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){…

}}

Page 27: Death of the batch job - NServiceBus Sagas

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

}}

Page 28: Death of the batch job - NServiceBus Sagas

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]

Page 29: Death of the batch job - NServiceBus Sagas

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

}

Page 30: Death of the batch job - NServiceBus Sagas

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

}

Page 31: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Death to the batch jobBecause we don’t want to depend on operations ;-)

Page 32: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Page 33: Death of the batch job - NServiceBus Sagas

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

Page 34: Death of the batch job - NServiceBus Sagas

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

Page 35: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Tromsø, Norway

Page 36: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

what if

we can see things before they happen?

Page 37: Death of the batch job - NServiceBus Sagas

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!

Page 38: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

-$300-$100

+$300

DURABLE TIMEOUTS

Our way to predict the future

2015 2016

+$100

Page 39: Death of the batch job - NServiceBus Sagas

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

}

Page 40: Death of the batch job - NServiceBus Sagas

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

}}

Page 41: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Best PracticesThe silver bullets?

Page 42: Death of the batch job - NServiceBus Sagas

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

Page 43: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Business eventsTimeoutsStarting sagas

out of order

Page 44: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

ASYNCHRONOUS COMMUNICATION

Order of message delivery

OrderAccepted

OrderAccepted

OrderBilled

Page 45: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

ASYNCHRONOUS COMMUNICATION

Order of message delivery

OrderAccepted

OrderAccepted

OrderBilled

Page 46: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

ASYNCHRONOUS COMMUNICATION

Order of message delivery

OrderAccepted

OrderAccepted

OrderBilled

OrderCancelled

How to solve?

Page 47: Death of the batch job - NServiceBus Sagas

race conditions do not exist

Page 48: Death of the batch job - NServiceBus Sagas

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

}}

Page 49: Death of the batch job - NServiceBus Sagas

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

}

Page 50: Death of the batch job - NServiceBus Sagas

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

}}

Page 51: Death of the batch job - NServiceBus Sagas

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

Page 52: Death of the batch job - NServiceBus Sagas

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

}

Page 53: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

CONCURRENCY

DELETE FROM ShoppingCartSagaDataWHERE 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 ShoppingCartSagaDataWHERE Id = '1C669378-3508-4A20-8EFD-A5C60168893E'AND RowVersion = 1

Page 54: Death of the batch job - NServiceBus Sagas

Sagas is business agility

Page 55: Death of the batch job - NServiceBus Sagas

http://bit.ly/nlnsbug

Page 56: Death of the batch job - NServiceBus Sagas

Dennis van der Stelt

Please…stay in touch!http://dennis.bloggingabout.net

[email protected]


Recommended