How to implement delete and delete-after-N-days in event sourcing

626 views
Skip to first unread message

Ron Liu

unread,
Aug 14, 2014, 7:51:48 AM8/14/14
to ddd...@googlegroups.com
Hi Guys, 

I am new to event sourcing, recently I am trying on my e-commerce project. Right now I am struggling with how to delete or delete-after-N-days cases. 

1. Delete:
I guess I should introduce a delted property in AbstractEventSourcedAggregate, and when delete command comes, just set this property to true. And when eventstore try to get an aggregate which has been set to deleted, it should return null. Is it right way to do it? 

2. Delete-after-N-days:
The case is shopping cart. we should delete cart items after N days. But who should send a command which will generate this events and when?


Thanks,
Ron

Dustin Wheeler

unread,
Aug 14, 2014, 9:26:28 AM8/14/14
to ddd...@googlegroups.com
Hey Ron!

The case you want to delete an aggregate, you might store a deleted property to maintain enough state to be able to hold the hypothetical invariant that the only command that can be issued from that point on to this specific aggregate is a "RestoreAggregateCommand".  You might have the repository wrapping an event store return null if it determines that an aggregate (after having all events applied to it) had a "deleted property" of "true".  Either way, what comes out of the event store is events, that's it.  They get applied to a specific aggregate as part of its history by a repository and the repository exposes the aggregate according to the constraints of its interface.

In the case you wanted to implement "delete after N days", I have in the past used sagas to pull this off.  Essentially each saga becomes an instance of a workflow that is defined by the behaviour you're seeking.  In this case, the saga would abstractly "recognize how many days have passed since creation" and then simply send a command to your application, deleting the item.  Greg Y. has a post on these forums I'll try to hunt down that describes this in more detail.  If I can't find it, I'll try to elaborate more.  But essentially, it's a long-running process that abstracts the rule you've described and simply sends a DeleteThisThingCommand when it's time (which is great because it just fits with the rest of your architecture, usually)

Dustin Wheeler

unread,
Aug 14, 2014, 9:27:58 AM8/14/14
to ddd...@googlegroups.com
More info in the quick:  http://cqrs.nu/Faq/sagas


--
You received this message because you are subscribed to a topic in the Google Groups "DDD/CQRS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dddcqrs/R5kZce_WCJg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Dustin Wheeler
Web Application Developer
College of Engineering, ITECS
North Carolina State University
Raleigh, NC 27695, x5-9786

dustin_...@ncsu.edu

Find my office with Google Maps:
http://go.ncsu.edu/find-dustin

Ron Liu

unread,
Aug 14, 2014, 10:05:36 AM8/14/14
to ddd...@googlegroups.com
Hi Dustin, 

For simple delete, I think I am on the right track. 

For delete-after-n-days, saga does make sense, but still need a time trigger, am I right? And how about just send a delayed message to delete when create? does this make sense?  

Thanks for you help,
Ron

Greg Young

unread,
Aug 14, 2014, 10:18:24 AM8/14/14
to ddd...@googlegroups.com
Some event stores such as event store support this internally $maxage on stream. A more generic solution can be seen however in process managers and delayed messaging see my talk from dddx this year on skills after website
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--
Studying for the Turing test

Kijana Woodard

unread,
Aug 14, 2014, 10:36:40 AM8/14/14
to ddd...@googlegroups.com
Fwiw, I think I remember Rinat Abdullin talking about falling out of favor with storing "future messages" in a separate timeout service. I was never very clear on the replacement, but it might have been just keeping all the timeouts in memory.

Greg Young

unread,
Aug 14, 2014, 10:37:52 AM8/14/14
to ddd...@googlegroups.com
We do in memory in event store but we also have limits as to how many can really be there

Kasey Speakman

unread,
Aug 14, 2014, 10:41:54 AM8/14/14
to ddd...@googlegroups.com
I recall him saying that he starts with projected views and letting a user be the process manager. Then automation options are evaluated as the process solidifies.


On Thursday, August 14, 2014 9:36:40 AM UTC-5, Kijana Woodard wrote:
Fwiw, I think I remember Rinat Abdullin talking about falling out of favor with storing "future messages" in a separate timeout service. I was never very clear on the replacement, but it might have been just keeping all the timeouts in memory.
On Thu, Aug 14, 2014 at 9:18 AM, Greg Young <gregor...@gmail.com> wrote:
Some event stores such as event store support this internally $maxage on stream. A more generic solution can be seen however in process managers and delayed messaging see my talk from dddx this year on skills after website


On Thursday, August 14, 2014, Dustin Wheeler <mdwh...@ncsu.edu> wrote:
Hey Ron!

The case you want to delete an aggregate, you might store a deleted property to maintain enough state to be able to hold the hypothetical invariant that the only command that can be issued from that point on to this specific aggregate is a "RestoreAggregateCommand".  You might have the repository wrapping an event store return null if it determines that an aggregate (after having all events applied to it) had a "deleted property" of "true".  Either way, what comes out of the event store is events, that's it.  They get applied to a specific aggregate as part of its history by a repository and the repository exposes the aggregate according to the constraints of its interface.

In the case you wanted to implement "delete after N days", I have in the past used sagas to pull this off.  Essentially each saga becomes an instance of a workflow that is defined by the behaviour you're seeking.  In this case, the saga would abstractly "recognize how many days have passed since creation" and then simply send a command to your application, deleting the item.  Greg Y. has a post on these forums I'll try to hunt down that describes this in more detail.  If I can't find it, I'll try to elaborate more.  But essentially, it's a long-running process that abstracts the rule you've described and simply sends a DeleteThisThingCommand when it's time (which is great because it just fits with the rest of your architecture, usually)

On Thursday, August 14, 2014 7:51:48 AM UTC-4, Ron Liu wrote:
Hi Guys, 

I am new to event sourcing, recently I am trying on my e-commerce project. Right now I am struggling with how to delete or delete-after-N-days cases. 

1. Delete:
I guess I should introduce a delted property in AbstractEventSourcedAggregate, and when delete command comes, just set this property to true. And when eventstore try to get an aggregate which has been set to deleted, it should return null. Is it right way to do it? 

2. Delete-after-N-days:
The case is shopping cart. we should delete cart items after N days. But who should send a command which will generate this events and when?


Thanks,
Ron

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Kijana Woodard

unread,
Aug 14, 2014, 10:47:00 AM8/14/14
to ddd...@googlegroups.com
Oh yes. Thanks for the reminder.

Ron Liu

unread,
Aug 15, 2014, 2:38:12 AM8/15/14
to ddd...@googlegroups.com
Just watched, helped me a lot to to understand the power of future message. Thanks. 



--
You received this message because you are subscribed to a topic in the Google Groups "DDD/CQRS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dddcqrs/R5kZce_WCJg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dddcqrs+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Best Regards,
Ron Liu
Mobile: +61 4 1163 7727
Email: ronl...@gmail.com

Ron Liu

unread,
Aug 15, 2014, 2:39:29 AM8/15/14
to ddd...@googlegroups.com
Hi Kasey, 

Could you give me a link I can learn from? 

Thanks,
Ron




--
You received this message because you are subscribed to a topic in the Google Groups "DDD/CQRS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dddcqrs/R5kZce_WCJg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dddcqrs+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Kasey Speakman

unread,
Aug 15, 2014, 9:33:20 AM8/15/14
to ddd...@googlegroups.com

Ron Liu

unread,
Aug 15, 2014, 9:56:49 AM8/15/14
to ddd...@googlegroups.com
Really good stuff, I appreciated.

Michael Schmidt

unread,
Aug 15, 2014, 10:18:03 AM8/15/14
to Kasey Speakman, ddd...@googlegroups.com
So if you use a future message, and the user touches that cart again, do you cancel the message so the user has another X days to keep their cart? or do you copy the cart to a new cart. If you do that you can delete the old cart right away.

I guess I need to see the video. Read some more about future messages.

Sent from my Windows Phone

From: Kasey Speakman
Sent: 8/15/2014 6:33 AM
To: ddd...@googlegroups.com
Subject: Re: [DDD/CQRS] How to implement delete and delete-after-N-days in event sourcing

Kasey Speakman

unread,
Aug 15, 2014, 10:33:53 AM8/15/14
to ddd...@googlegroups.com
Here is his followup post. The link in the other post was broken.

Ron Liu

unread,
Aug 15, 2014, 10:43:14 AM8/15/14
to ddd...@googlegroups.com, Kasey Speakman
Hi Michael, 

I think I will expire the cart only based on createdOn, which means touching again will not extend. 

If I really want to extend, based on Grey's future message talk, I guess we should add a number(like a sign) into message schema, so 
1. it sent a future message with 1 and expiry date is N day after yesterday, assume cart was created yesterday;
2. when user touch it
    a. send a message straight away with -1 and date is N days after now which means cancel any future message whose date is before N days after now
    b. send another future message again with 1 and date is N days after now. 

Hopefully it make sense.

By the way, I feel a little bit it is overkilled to use future message to expire a cart, I am not sure if projection can do the same job. 


Cheers,
Ron 

Kijana Woodard

unread,
Aug 15, 2014, 10:47:25 AM8/15/14
to ddd...@googlegroups.com
side note: Greg not Grey.

Ron Liu

unread,
Aug 15, 2014, 10:51:16 AM8/15/14
to ddd...@googlegroups.com
Oh, really sorry for that serious typo, I feel so sad. Forgive me.

Kijana Woodard

unread,
Aug 15, 2014, 11:11:05 AM8/15/14
to ddd...@googlegroups.com
The general approach I've seen when using "future messages" that are irrelevant is just to allow them to fire and ignore them.

Kijana Woodard

unread,
Aug 15, 2014, 11:22:11 AM8/15/14
to ddd...@googlegroups.com
@Kasey, since you found the posts I was originally referencing, here is the one you were originally referencing: 

"You simply wire view to the UI, attach a button to send "lockdown command" and ask a person from the business department to spend half an hour per week processing all late customers."

Kasey Speakman

unread,
Aug 15, 2014, 11:24:14 AM8/15/14
to ddd...@googlegroups.com
Nice, thank you. :)

Ron Liu

unread,
Aug 15, 2014, 11:31:16 AM8/15/14
to ddd...@googlegroups.com
Very concise, I really should read every single blog. Thanks for this wonderful source. 

Kijana Woodard

unread,
Aug 15, 2014, 11:35:43 AM8/15/14
to ddd...@googlegroups.com
They are very good. 

Rinat provides ample warning in the text, but he's constantly refining his approach, so don't be surprised contradictions between posts.

Ron Liu

unread,
Aug 15, 2014, 12:01:32 PM8/15/14
to ddd...@googlegroups.com
@Kijana, the article you mentioned is great, it provides all possible ways to solve time triggering processing. If I am right, mainly 4 as below:
1. state machine + future message
2. projection
3. manual process
4. scheduled task

IMO, for cart scenario, I think
#1. possible, but feel a bit overkilled since cart expiry only has simple logic. 
#2. possible, the simplest way to do that is query the projection with where conditions
#3. N/A
#4. not possible, every 1 hour send message to all customer aggregate, doesn't make sense. 

I may try #2 first, and #1 is backup.   

Kasey Speakman

unread,
Aug 15, 2014, 12:05:41 PM8/15/14
to ddd...@googlegroups.com
For #4, it has to be combined with #2. The task wakes up every day and queries the projection. If it finds some old carts, it sends a command to expire/delete them. The events resulting from that command then removes them from the projection too. Tomorrow when task runs again, they aren't there.

Ron Liu

unread,
Aug 15, 2014, 12:17:44 PM8/15/14
to ddd...@googlegroups.com
Good point. #2 just simply push all the responsibility to who use this projection, I mean who use this project need filter itself. but #4 will clean up the projection but as a cost it need iterator all customers every certain time. So does #1, but it just need a future message. Compared with #4, in cart scenario, #1 may be cheaper. 

Kijana Woodard

unread,
Aug 15, 2014, 12:20:54 PM8/15/14
to ddd...@googlegroups.com
Not every customer every time.
You have a specialized projection for "this cart needs to be checked".

Once the command is handled, the projection will resolve the resulting event and clear itself.
The timeout loop will only have to deal with "pending carts".

Ron Liu

unread,
Aug 15, 2014, 8:46:59 PM8/15/14
to ddd...@googlegroups.com
Yes, you are right, it can be narrowed down.

Rinat Abdullin

unread,
Aug 16, 2014, 7:46:57 AM8/16/14
to ddd...@googlegroups.com
Hi folks,

thank you for mentioning broken links in my blog, I just pushed update fixing them and adding some missing pictures.

Re patterns. Although I'm still learning, I think, there are two groups of patterns applicable to business processes:

1. Design patterns that help you capture requirements or defer decisions (event-storming, projecting data to UI and letting people make the decisions, explicit use cases, domain modeling sessions with experts etc)
2. Design patterns for implementing captured requirements: future messages, sagas, recurrent tasks etc.

I think, that #1 is the hardest and most interesting part. Once you have it, #2 is mostly just an implementation detail that is not so relevant. If code is hidden inside "black box" that is covered with use cases, you could always discard it, replacing with another implementation. Nobody will probably ever notice.

Best regards,
Rinat



Rinat Abdullin | Writer at Abdullin.com

Ron Liu

unread,
Aug 19, 2014, 10:49:12 AM8/19/14
to ddd...@googlegroups.com
Hi Rinat,

Thanks for your updates, I saw the pictures. 

Also for the two patterns, it's good. Implementation only work for requirements, move on and replace it later if needed. 


Cheers,
Ron

Michael Schmidt

unread,
Aug 19, 2014, 11:34:54 AM8/19/14
to Ron Liu, ddd...@googlegroups.com, Kasey Speakman
Yes, it does seem like a poor use of future messages. We don't use any of this (ddd) , but our carts are expired by deletion by a job. Old school.


Sent from my Windows Phone

From: Ron Liu
Sent: 8/15/2014 7:43 AM
To: ddd...@googlegroups.com
Cc: Kasey Speakman

Subject: Re: [DDD/CQRS] How to implement delete and delete-after-N-days in event sourcing

Hi Michael, 

I think I will expire the cart only based on createdOn, which means touching again will not extend. 

If I really want to extend, based on Grey's future message talk, I guess we should add a number(like a sign) into message schema, so 
1. it sent a future message with 1 and expiry date is N day after yesterday, assume cart was created yesterday;
2. when user touch it
    a. send a message straight away with -1 and date is N days after now which means cancel any future message whose date is before N days after now
    b. send another future message again with 1 and date is N days after now. 

Hopefully it make sense.

By the way, I feel a little bit it is overkilled to use future message to expire a cart, I am not sure if projection can do the same job. 


Cheers,
Ron 
You received this message because you are subscribed to a topic in the Google Groups "DDD/CQRS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dddcqrs/R5kZce_WCJg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Best Regards,
Ron Liu
Mobile: +61 4 1163 7727
Email: ronl...@gmail.com

Greg Young

unread,
Aug 19, 2014, 12:07:27 PM8/19/14
to ddd...@googlegroups.com, Ron Liu, Kasey Speakman
"Yes, it does seem like a poor use of future messages. We don't use any of this (ddd) , but our carts are expired by deletion by a job. Old school."

Umm what is your job? Its just a specific (poorly done) implementation of a future message no?

Andrew Browne

unread,
Aug 20, 2014, 10:41:49 PM8/20/14
to ddd...@googlegroups.com
Hi Guys,

Something that has worked well for us in some parts of our application is instead of publishing future messages that contain content we basically use projections to keep track of the next time that each aggregate wants to be "woken up". This makes cancelling future messages irrelevant.

The steps work like this:
1. Normal aggregate commands and events.
2. We have a projection that subscribes to all events of the aggregate and keeps track of what the next wakeup time (if any) is.
3. When the wakeup time is reached we load the aggregate state and let it produce new events.
4. These new events should either update or remove the wakeup time.

In the case where a command changes the wakeup time then the projection just moves the wakeup time earlier or later - previous request is effectively cancelled. In the case of these things occurring close together because the wakeup loads aggregate state and checks that the wakeup time is the same as the callback - if not it's moved and we do nothing until the new wakeup time.

This is less flexible than what Greg describes in his video but if your aggregates are modelled in a way where the wakeup time can be computed as part of aggregate state and the future events are to be written to the same aggregate this makes things very simple.

cheers
Andrew

Ron Liu

unread,
Aug 20, 2014, 11:09:56 PM8/20/14
to ddd...@googlegroups.com
Andrew, thanks for your update. If I understand well, you will inject the wake-up logic into all events handlers of the aggregate. But how about if there are no events triggered for this aggregate for a long time, this wake-up logic will not get chance to apply, and the read model will keep stale. 

Cheers,
Ron

Greg Young

unread,
Aug 20, 2014, 11:55:57 PM8/20/14
to ddd...@googlegroups.com
How is this different than a future message

Andrew Browne

unread,
Aug 20, 2014, 11:57:42 PM8/20/14
to ddd...@googlegroups.com
Hi Ron,

You are right - conceptually the wakeup time logic runs at the end of each event handler.

RE: no events for along time. That is the caveat at the end: "the wakeup time can be computed as part of aggregate state" - so the wakeup time can be computed using only the events in the aggregate (presuming event sourcing).

If the wakeup time is only computed based on the aggregate state then there is no way for it to change unless there has been new events saved into that aggregate - so if there are no events then the wakeup time cannot be changing and will not be stale. If you want the wakeup time to depend on things external to the aggregate then you either need to either need to change the way you model your problem or find a different solution.

Does that make sense?

cheers
Andrew

Greg Young

unread,
Aug 20, 2014, 11:59:04 PM8/20/14
to ddd...@googlegroups.com
This is how future / delayed messages work as well unless I'm missing something


On Wednesday, August 20, 2014, Andrew Browne <bro...@brownie.com.au> wrote:

Ron Liu

unread,
Aug 21, 2014, 12:21:15 AM8/21/14
to ddd...@googlegroups.com
Hi Andrew,

I may miss something. Can we give an example to elaborate on? Still use cart, the business logic is: cart item should be removed N days after it is created. 

Cart aggregate will have 2 kinds of events: cartItemRemoved and cartItemAdded. So I guess in both events handlers, your solution will check if it is expired, if it is then raise another event called cartItemExpired, then in cartItemExpired event handler you will remove the expired cart items. Am I right so far? if it is the case, the items will never be expired if user didn't operate cart for a long time. 

I guess cart scenario doesn't fit on your solution, because "timer" is out of the aggregate. 


Thanks,
Ron

Andrew Browne

unread,
Aug 21, 2014, 2:03:53 AM8/21/14
to ddd...@googlegroups.com
Hi Greg,

Yes I'm really just rearranging things so that rather than put any state in the delayed message it just comes back with the time and I use that to work out whether to action the message or not. In my case that worked out to be a much simpler way to arrange the logic rather than model cancellation explicitly. You could completely implement my solution with normal delayed messages.

cheers
Andrew

Andrew Browne

unread,
Aug 21, 2014, 3:17:20 AM8/21/14
to ddd...@googlegroups.com
Hi Ron,

I do not check if there are any expired items in the command handlers - after each command handler is run I just calculate the new wakeup time. Behind the scenes the infrastructure just creates a future publish or equivalent for that time.

Maybe this scenario will help:

I'm ignoring the command handlers that emit the added and removed events. The aggregate state could be modelled like this (sorry f# syntax):

type CartState = {
    // dictionary of itemid to expiry
    Items: Map<Guid,DateTime>
}

Our state building function would be something like this to build up the list items and their expiries:
let buildState (state: CartState) (event: CartEvent) =
    match event with
    | Added evt ->
        state.Items |> Map.add evt.ItemId (evt.DateAdded.AddDays(3.0))
    | Removed evt ->
        state.Items |> Map.remove evt.ItemId
    | Expired evt ->
        state.Items |> Map.remove evt.ItemId

The extra function we have with our aggregate is the next wakeup function. It returns the next wakeup time and the events to be emitted at that time.

let nextWakeupEvent (state : CartState) : Option<DateTime * list<CartEvent>> =
    if(state.Items.IsEmpty) then
        None
    else
        let nextExpiryDate = 
            state.Items
            |> Map.toSeq
            |> Seq.minBy(fun (itemId,expiry) -> expiry)
            |> snd

        let expiryEventsForNextDate = 
            state.Items 
            |> Map.toList
            |> List.filter (fun (itemId, expiry) -> expiry <> nextExpiryDate)
            |> List.map (fun (itemId, expiry) -> Expired { ItemId = itemId })

        Some (nextExpiryDate, expiryEventsForNextDate)

The nextWakeupEvent is called in two different scenarios. After each command handler run then we calculate the new state of the aggregate state and pass it to nextWakeupEvent to get the new the wakeup time - it then does a future publish behind the scenes to come back at the date returned (if there was one).

When the future message comes back the infrastructure will run the function again. One of two scenarios will be true: The date on the future message matches the date returned by out nextWakeupEvent function and we save the Expired events - or it does not match in which case we ignore the message (it has been effectively cancelled).

Image the following scenario:
1. (1 Jan 2014) User Adds Item 'Foo' To Cart: CartItemAddedEvent event is emitted. Wakeup time is calculated to be 4 Jan (3 days ahead).
2. (2 Jan 2014) User Removes Item 'Foo' from cart:
CartRemovedEvent is emitted. Wakeup time is None because cart is now empty again.
3. (3 Jan 2014) User Adds Item 'Bar' to cart:
CartItemAdded event is emitted. Wakeup time is calculated to be 6 Jan (3 days ahead)
4. (4 Jan 2014) Depending on the implementation the original future publish event is received when the nextWakeupEvent function is called the date does not match as it's now the 6th - the message is ignored.
5. (6 Jan 2014) New wakeup - nextWakeupEvent function is called and the date matches. The expired event is emitted for item 'Bar'. Wakeup time is now None again since the cart is empty.

Hope this makes more sense? As Greg pointed out this is really just a special case of future messages.

cheers
Andrew

Michael Schmidt

unread,
Aug 21, 2014, 4:03:10 AM8/21/14
to Greg Young, ddd...@googlegroups.com, Ron Liu, Kasey Speakman
Except its not a "message" its a db script. Our carts are kept in a relational db using XML. Don't even get me started.

Since its db code, compares a date, deletes a record, I have a hard time calling it a message. A command yes "delete cart"...


Sent from my Windows Phone

From: Greg Young
Sent: 8/19/2014 9:07 AM
To: ddd...@googlegroups.com
Cc: Ron Liu; Kasey Speakman

Subject: Re: [DDD/CQRS] How to implement delete and delete-after-N-days in event sourcing

"Yes, it does seem like a poor use of future messages. We don't use any of this (ddd) , but our carts are expired by deletion by a job. Old school."

Umm what is your job? Its just a specific (poorly done) implementation of a future message no?
On Tue, Aug 19, 2014 at 11:34 AM, Michael Schmidt <mikeyw...@gmail.com> wrote:
Yes, it does seem like a poor use of future messages. We don't use any of this (ddd) , but our carts are expired by deletion by a job. Old school.
Sent from my Windows Phone
From: Ron Liu
Sent: 8/15/2014 7:43 AM
To: ddd...@googlegroups.com
Cc: Kasey Speakman
Subject: Re: [DDD/CQRS] How to implement delete and delete-after-N-days in event sourcing

Hi Michael, 

I think I will expire the cart only based on createdOn, which means touching again will not extend. 

If I really want to extend, based on Grey's future message talk, I guess we should add a number(like a sign) into message schema, so 
1. it sent a future message with 1 and expiry date is N day after yesterday, assume cart was created yesterday;
2. when user touch it
    a. send a message straight away with -1 and date is N days after now which means cancel any future message whose date is before N days after now
    b. send another future message again with 1 and date is N days after now. 

Hopefully it make sense.

By the way, I feel a little bit it is overkilled to use future message to expire a cart, I am not sure if projection can do the same job. 


Cheers,
Ron 
--
You received this message because you are subscribed to a topic in the Google Groups "DDD/CQRS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dddcqrs/R5kZce_WCJg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dddcqrs+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Best Regards,
Ron Liu
Mobile: +61 4 1163 7727
Email: ronl...@gmail.com

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Studying for the Turing test

Andrew Browne

unread,
Aug 21, 2014, 4:22:21 AM8/21/14
to ddd...@googlegroups.com
Correction 
|> List.filter (fun (itemId, expiry) -> expiry <> nextExpiryDate)

should be

|> List.filter (fun (itemId, expiry) -> expiry = nextExpiryDate)

Ron Liu

unread,
Aug 21, 2014, 5:37:37 AM8/21/14
to ddd...@googlegroups.com
Hi Andrew,

Good explanation, it is future message, the main point is how to cancel future message: saving the exact expiry date as part of aggregate state.

Thanks for your sharing, I appreciated. 

Ron

Greg Young

unread,
Aug 21, 2014, 9:12:48 AM8/21/14
to ddd...@googlegroups.com
You don't cancel future messages you just reach a state where you ignore them if needed.

Ron Liu

unread,
Aug 21, 2014, 9:44:39 AM8/21/14
to ddd...@googlegroups.com
Exactly, thanks for correction.

Greg Young

unread,
Aug 22, 2014, 12:15:15 PM8/22/14
to ddd...@googlegroups.com
Messages are assured to come at that point in time or after. Accuracy has little to do with it.

You can just as easily schedule a message that runs a batch job 

On Friday, August 22, 2014, Ron Liu <ronl...@gmail.com> wrote:
IMO, The difference between scheduled job and future message are: 
1. If we doesn't care the accuracy, scheduled job is a better option, because it is easy. Like cart expiration case, the requirement should be expired in 2 hours, but it doesn't matter if it really expired in 2 hours and 1minute.  

2. If we do care the accuracy, has to use future message, like reserve patter used in movie ticket sale case, the requirement is the order should be expired in exact 15 minutes

On Thursday, 21 August 2014 23:26:35 UTC+10, Kijana Woodard wrote:
That's just an, unfortunate, implementation detail.

The scheduled job run itself is the "future message".

From: Michael Schmidt
Sent: ‎8/‎21/‎2014 3:03 AM
To: Greg Young; ddd...@googlegroups.com
Subject: RE: [DDD/CQRS] How to implement delete and delete-after-N-days inevent sourcing

Except its not a "message" its a db script. Our carts are kept in a relational db using XML. Don't even get me started.

Since its db code, compares a date, deletes a record, I have a hard time calling it a message. A command yes "delete cart"...

Sent from my Windows Phone
From: Greg Young
Sent: 8/19/2014 9:07 AM
To: ddd...@googlegroups.com
Cc: Ron Liu; Kasey Speakman
Subject: Re: [DDD/CQRS] How to implement delete and delete-after-N-days in event sourcing

"Yes, it does seem like a poor use of future messages. We don't use any of this (ddd) , but our carts are expired by deletion by a job. Old school."

Umm what is your job? Its just a specific (poorly done) implementation of a future message no?
On Tue, Aug 19, 2014 at 11:34 AM, Michael Schmidt <mikeyw...@gmail.com> wrote:
Yes, it does seem like a poor use of future messages. We don't use any of this (ddd) , but our carts are expired by deletion by a job. Old school.
Sent from my Windows Phone
From: Ron Liu
Sent: 8/15/2014 7:43 AM
To: ddd...@googlegroups.com
Cc: Kasey Speakman
Subject: Re: [DDD/CQRS] How to implement delete and delete-after-N-days in event sourcing

Hi Michael, 

I think I will expire the cart only based on createdOn, which means touching again will not extend. 

If I really want to extend, based on Grey's future message talk, I guess we should add a number(like a sign) into message schema, so 
1. it sent a future message with 1 and expiry date is N day after yesterday, assume cart was created yesterday;
2. when user touch it
    a. send a message straight away with -1 and date is N days after now which means cancel any future message whose date is before N days after now
    b. send another future message again with 1 and date is N days after now. 

Hopefully it make sense.

By the way, I feel a little bit it is overkilled to use future message to expire a cart, I am not sure if projection can do the same job. 


Cheers,
Ron 
--
You received this message because you are subscribed to a topic in the Google Groups "DDD/CQRS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dddcqrs/R5kZce_WCJg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dddcqrs+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Best Regards,
Ron Liu
Mobile: +61 4 1163 7727
Email: ronl...@gmail.com

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Studying for the Turing test

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages