Re: [masstransit-discuss] Starbucks Example Concurrency Issues

128 views
Skip to first unread message

Travis Smith

unread,
Apr 17, 2013, 1:15:40 PM4/17/13
to masstrans...@googlegroups.com
I have done some work on cleaning up this sample, including moving it to RabbitMQ. I think what you've described is a problem and we should limit the customer's ability to order something new. You can, with my branch (https://github.com/MassTransit/MassTransit/pull/176), have multiple customer instances and it works without a problem. I'll take a look at how we might want to address this. It might be the unsubscribe is unneeded now. 

Most of the time I don't bother unsubscribing. It's only if you want to stop receiving messages. 



-Travis


On Wed, Apr 17, 2013 at 12:18 PM, Doug Wilson <doug.k...@gmail.com> wrote:
In the Starbucks example, prior to the customer publishing the NewOrderMessage, the following code is present:

if (_unsubscribeToken != null)
_unsubscribeToken();
_unsubscribeToken = Bus.SubscribeInstance(this);

I'm trying to understand the purpose of the unsubscribe token and when it's needed/not needed.  However, the example app seems to be broken in the following scenario:
  1. Customer sends NewOrderMessage#1
  2. Cashier processes NewOrderMessage#1 and publishes PaymentDueMessage#1
  3. Barista processes NewOrderMessage#1
  4. Customer processes PaymentDueMessage#1 and publishes SubmitPaymentMessage#1
  5. Cashier processes SubmitPaymentMessage#1 and publishes PaymentCompleteMessage#1
  6. Prior to Barista completing processing of NewOrderMessage#1 Customer publishes another NewOrderMessage#2
  7. Barista is now simultaneously processing NewOrderMessage#1 and NewOrderMessage#2
  8. Barista completes processing NewOrderMessage#1 and publishes DrinkReadyMessage#1
  9. Customer does not Receive DrinkReadyMessage#1
  10. Barista completes processing NewOrderMessage#2 and publishes DrinkReadyMessage#2
  11. Customer processes DrinkReadyMessage#2
When I check the queues in RabbitMQ, the starbucks_customer_error queue has the missing DrinkReadyMessage#1.  I believe this is because the unsubscribeToken issued prior to publishing NewOrderMessage#1 was called during the second order effectively cancelling the subscription for the first order.

In trying to fix this, I setup a Dictionary<Guid, UnsubscribeAction> using the CorrelationId as the key and then invoke the token after the DrinkReadyMessage is received. Doing this allows DrinkReadyMessage#1 through but now DrinkReadyMessage#2 is published by the Barista but is never received by the Customer and doesn't appear in any queues, error or otherwise. ( https://gist.github.com/Hellfire/5405606 )

In effect, I've made the problem worse than before. 

Help!

NOTE: I am using RabbitMQ 3.0.4, Erlang R16B and MassTransit from https://github.com/MassTransit/MassTransit

--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-dis...@googlegroups.com.
To post to this group, send email to masstrans...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/masstransit-discuss/-/SA3DBubKF8AJ.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Chris Patterson

unread,
Apr 18, 2013, 1:26:50 PM4/18/13
to masstrans...@googlegroups.com
With the consumer app, it's a correlated subscription, so yeah, it needs to be unsubscribed once it is done. The issue is that the correlated subscription stuff is pretty limited if you aren't creating a new consumer instance with the proper correlation Id for each request from the consumer.

Doug Wilson

unread,
Apr 18, 2013, 5:44:39 PM4/18/13
to masstrans...@googlegroups.com
Thanks for jumping on this Travis.

I've merged your changes but still observe the same behavior.  Because of the correlated subscription would it make sense to have a unique Customer instance per order and then call Bus.SubscribeInstance(customer)?  That instance would then be "listening" for the DrinkReadyMessage and call the unsubscribeToken.

For the sake of the example, maybe the UI compponent becomes the "Store" and owns responsibility for managing the customer lifetime.

I'm new to github, pull requests and such but if I'm on the right track I'd love to code it up and submit it, assuming you don't mind coaching me through the github incantations.

-dw

Travis Smith

unread,
Apr 18, 2013, 5:51:07 PM4/18/13
to masstrans...@googlegroups.com, masstrans...@googlegroups.com
You're welcomed to take a swing at changing the sample. And don't worry about the GitHub stuff. We can help with that. Just commit often and make sure core.autocrlf is set to false. 

-Travis
--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-dis...@googlegroups.com.
To post to this group, send email to masstrans...@googlegroups.com.

Doug Wilson

unread,
Apr 19, 2013, 2:26:11 PM4/19/13
to masstrans...@googlegroups.com
Okay... I'm completely stumped.

I've experimented with a number of different ways of managing multiple UnsubscribeActions but in every case it seems that there can only be one "active" UnsubscribeAction per IServiceBus instance.  If a new one is generated before the previous one has been invoked then any messages generated for the original correlationId end up in an _error queue or disappear entirely.

I'm certain I am just misunderstanding how this all works but shouldn't MT keep track of the tokens and honor them until they've been invoked?

-dw

Chris Patterson

unread,
Apr 20, 2013, 9:06:56 PM4/20/13
to masstrans...@googlegroups.com
Take a look at how the form implements Consumes<DrinkReadyMessage>.For<string>. That's looking at the property CorrelationId on the form, which is the name of the last submitted drink. You would need to remove from consumer from the form and keep track of multiple consumers for each submitted order, each with their own correlated consumer.


--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-dis...@googlegroups.com.
To post to this group, send email to masstrans...@googlegroups.com.

Doug Wilson

unread,
Apr 22, 2013, 2:37:03 PM4/22/13
to masstrans...@googlegroups.com
Thanks Chris,

That was what I tried first:  https://gist.github.com/Hellfire/5405606

So what ends up happening with that is that the first order completes fully with the Customer instance receiving the DrinkReadyMessage.  However, the 2nd order (issued before the first completes) only gets the payment message.  The final DrinkReadyMessage is sent by the barista instance but it is never received by the customer instance, and worse, it doesn't show up in an _error queue either.

dw

Doug Wilson

unread,
Apr 24, 2013, 2:00:33 PM4/24/13
to masstrans...@googlegroups.com
Does each Customer need it's own instance of IServiceBus or should IServiceBus be a Singleton?

Doug Wilson

unread,
Apr 29, 2013, 2:54:29 PM4/29/13
to masstrans...@googlegroups.com
I hate to beg but I really need help with this.  At least tell me if I am barking up the wrong tree...  Am I seeing problems where there are none?

We're just getting started with messaging and I really want to be able to use MassTransit but if I can't solve something trivial in sample code like this then I worry that we're going to run into much bigger problems with MT down the road.

Dru Sellers

unread,
Apr 29, 2013, 2:58:33 PM4/29/13
to masstrans...@googlegroups.com
Each customer needs its own IServiceBus and Endpoint Address

Q: is each customer in its own process?



--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-dis...@googlegroups.com.
To post to this group, send email to masstrans...@googlegroups.com.

Doug Wilson

unread,
Apr 29, 2013, 3:43:46 PM4/29/13
to masstrans...@googlegroups.com
A: No, I added a Customer class and then had the OrderDrinkForm create a new instance of it for each order.  However, I haven't tried it yet with each customer getting it's own bus and address.  I will give that a go.

Thanks!
To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-discuss+unsub...@googlegroups.com.

To post to this group, send email to masstrans...@googlegroups.com.

Chris Patterson

unread,
Apr 29, 2013, 4:28:15 PM4/29/13
to masstrans...@googlegroups.com
That seems overly wasteful. The break out of the consumer should be enough - why it isn't working I don't know.

Doug Wilson

unread,
Apr 29, 2013, 4:52:24 PM4/29/13
to masstrans...@googlegroups.com
In any case it doesn't work.  It seems to ignore the correlationId and all the customers receive all the PaymentDue and all the DrinkReady messages.

Either I'm really not understanding how this is supposed to work (likely) or there is a problem with managing subscribers.


On Monday, April 29, 2013 1:28:15 PM UTC-7, Chris Patterson wrote:
That seems overly wasteful. The break out of the consumer should be enough - why it isn't working I don't know.
On Mon, Apr 29, 2013 at 11:58 AM, Dru Sellers <d...@drusellers.com> wrote:
Each customer needs its own IServiceBus and Endpoint Address

Q: is each customer in its own process?

On Mon, Apr 29, 2013 at 1:54 PM, Doug Wilson <doug.k...@gmail.com> wrote:
I hate to beg but I really need help with this.  At least tell me if I am barking up the wrong tree...  Am I seeing problems where there are none?

We're just getting started with messaging and I really want to be able to use MassTransit but if I can't solve something trivial in sample code like this then I worry that we're going to run into much bigger problems with MT down the road.


On Wednesday, April 24, 2013 11:00:33 AM UTC-7, Doug Wilson wrote:
Does each Customer need it's own instance of IServiceBus or should IServiceBus be a Singleton?

On Monday, April 22, 2013 11:37:03 AM UTC-7, Doug Wilson wrote:
Thanks Chris,

That was what I tried first:  https://gist.github.com/Hellfire/5405606

So what ends up happening with that is that the first order completes fully with the Customer instance receiving the DrinkReadyMessage.  However, the 2nd order (issued before the first completes) only gets the payment message.  The final DrinkReadyMessage is sent by the barista instance but it is never received by the customer instance, and worse, it doesn't show up in an _error queue either.

dw

On Saturday, April 20, 2013 6:06:56 PM UTC-7, Chris Patterson wrote:
Take a look at how the form implements Consumes<DrinkReadyMessage>.For<string>. That's looking at the property CorrelationId on the form, which is the name of the last submitted drink. You would need to remove from consumer from the form and keep track of multiple consumers for each submitted order, each with their own correlated consumer.


On Fri, Apr 19, 2013 at 11:26 AM, Doug Wilson <doug.k...@gmail.com> wrote:
Okay... I'm completely stumped.

I've experimented with a number of different ways of managing multiple UnsubscribeActions but in every case it seems that there can only be one "active" UnsubscribeAction per IServiceBus instance.  If a new one is generated before the previous one has been invoked then any messages generated for the original correlationId end up in an _error queue or disappear entirely.

I'm certain I am just misunderstanding how this all works but shouldn't MT keep track of the tokens and honor them until they've been invoked?

-dw


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

To post to this group, send email to masstrans...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/masstransit-discuss/-/KGQ2m4RS7mYJ.

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

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

Doug Wilson

unread,
Apr 29, 2013, 5:19:12 PM4/29/13
to masstrans...@googlegroups.com
Dru's question on whether each customer was in its own process got me thinking... I haven't tried running multiple instances of the Customer program.  I did that with a clean checkout and voila, overlapping "orders" complete successfully.  I suppose that's expected.

However, at least on my machine, there is an _error queue and _error exchange created for each customer and after each process has completed each _error queue contains a DrinkReadyMessage even though each Customer process received it and displayed the appropriate dialog.

I think it's because CustomerA receives both their DrinkReadyMessage and the DrinkReadyMessage for CustomerB but because the second message isn't intended for them it ends up in their _error queue.  Same for CustomerB.

Thoughts?

Incidentally, I still want to get this working with one Customer process being able to issue and complete multiple simultaneous orders but I suspect there is something at the App Domain level that may not permit this, or, I'm still not understanding how Queues and Exchanges work together and haven't hit on the correct combination to facilitate this.  

Travis Smith

unread,
May 2, 2013, 10:21:21 AM5/2/13
to masstrans...@googlegroups.com
The way Customer part of this sample is setup might not even be the right way to interact with MT. It's mostly to showcase some options you have. Maybe an high level overview of what you think you want to do and then we can help nudge you in the right direction? 

If you're using my branch, multiple Consumer instances running will work simultaneously. If you're using master, then multiple Customers will read from the same queue and just mess you up. 

-Travis


To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-dis...@googlegroups.com.

To post to this group, send email to masstrans...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages