If you are using read-only cart or full-serializable value-object/DTO ([d]ata [t]ransfer [o]bjects by Marinescu et al) it isn't a problem.
You are using syntactic sweet "var", so I can't know, is there any value object for cart or remotable interface. In a second case you should use access-management functionality or you can run into stale or even inconsistent data. So or better (:
It's hard to say given the lack of context. Perhaps you should be building up the shopping cart on the web server, and then sending it to the app server when it's ready to be processed?
I'm probably way off the mark here, but your code implies that a shopping cart will always exist for a customer.
A shopping cart is a temporal entity that exists at a certain time - in other words a customer will have multiple shopping carts in the database. Therefore this service call will have to get the current shopping cart, and if one doesn't exist, it will create it.
Having a getter service call which does a "create if not exist" is going to be a problem, especially when it comes to concurrency.
Is customerSrv bound to a specific server instance?
The highest instability is there, if customerSrv is a pooled instance connected to a fixed server instance. This will prevent any failovers, making the call unstable.
As for the rest, by the picture and the single line of code I cannot see anything that must be unstable by the given evidence. I assume that you have put a nice try/catch/finally around it etc...
Well, this is probably wrong but it would appear that if each tier is load balanced (and we are not using some sort of sessions to ensure that calls from a client are always routed to the same machines) then subsequent calls to the GetShoppingCart method can return different carts. And multiple updates can overwrite changes that have been made to the cart.
So the instability would be a design issue rather than a implementation related side affect?
In WCF, you need to wrap that call in try-finally block and call customerSrv.Close() in the finally. Also call customerSrv.Abort() if the customerSrv.Close() throws an exception.
WCF is a connected technology, so you can insert a sort of Service Dispatcher in your architecture in order to have for each client a "private" set of services without passing every time the customerId.
Thank you, Orin, picture started to look much better =)
So the question was - not 'invalid code', but 'unstable'?
So, you are stating that this code can become 'bad' due to special circumstances. It is left to search out those circumstances you are mentioning =)
For the first time I see that if you started to play with transaction level from serializable to at least "dirty read" on db server, you can have dirty data in DTO.
Let's start to explore further =-) Hope don't annoy you so much
GetShoppingCart is a method pointed to a database Stored Procedure or function, so the Database programmer can change it without assent, and the "contract" become invalid.
thank you a lot for this question, it was really useful and interesting to ortogonate my view =)
But, I still thinking, that the problem of blocking of such type should be solved by another application logic layer (by building and configuring communication facilitites - thru AOP weaving and so on), and not directly by hi-level API - so configuration is not so perfect ;)
You wrote "no configuration mistakes". I'm not into WCF and if it's such a lousy crap that I cannot configure global timeouts, it's not worth looking at it...
So, what's the recommended way to fix the possibility of blocking? Something I thought of is the following:
Since we seem to be using a message oriented transport mechanism, we can treat each call as state in a state machine. After having made the call, we can put aside this state machine and process more messages. When we receive a message with the cart from the AppServer or the DB we proceed with whatever we were going to do to the cart. Periodically, we check to see how long any state machine is in a 'wait' state and then mark the required ones as timed out...and display a error message to the user or the like.
Hmm... surely whether to make Async calls to the service layer or not is a scalability issue rather than a stability issue? Here you are blocking worker threads meaning your app can't scale and process more requests?
Really!? Ouch - how could that be, especially in a stateless web application, can you explain? I've never experienced other threads being blocked whilst making a sync service call. Even an Async call is essentially a sync call but done in another thread or using an iocompletion port. Or are you saying we should be making duplex service calls to avoid possible problems?
I'm currently working on developing an inherited financial application and there are loads of sync calls to WCF services. So far we've had no problems but don't want them to bite us in the future! :-S
Oren and I have had an off-post dialogue about this. In short, I believe that he disagrees with my premise on the basis that he feels that my assumptions are wrong (not wishing to put words into his mouth).
Anyway, I thought it would be useful to post some of the links that I passed to Oren during the discussion so readers can make up their own minds.
It may make more sense when you consider that server cookies are not permitted in REST. Also note that Roy addresses the question of application state in [1] below. If you promote the cart up to being a full resource, then we are talking a different game. For a start, we are no longer looking at a traditional ecommerce platform cart implementation (if the promotion is RESTful, that is). For one thing, the cart state would have no relationship with an individual (that is to say, all people with the same cart contents would reference the same cart resource). Given that your example specifies a customerId, it doesn't seem to fit the RESTful model (it would if it took cartId instead).
"REST goes further and constrains application state (not resource state) to be held on the client. […] we can think of it as the context between user agent requests: the server cannot be aware of any such context and still be REST." Roy Fielding [1]
"Authentication is orthogonal. Cookies are also orthogonal when they are simply used for content negotiation or authentication. However, Cookie authentication is not allowed in REST because it lacks visibility, which causes security problems […]" Roy Fielding [2]
"Stateless in REST refers to the ability of the server to not know about prior requests in order to completely understand the current request." Roy Fielding [3]
"Application state in REST is what most distributed systems would call session state or transaction state, depending on which end of the system is being talked about. " Roy Fielding [4]
In the scenario where the cart is considered a resource as well, what exactly is wrong with using the customer id to identify the cart itself? Specially given that every customer can have at most one cart. I am just trying to think what makes storing a cart id more RESTful than storing a customer id since at the end of the day, the client side will have to send a number to the server ('customerSvr/carts/customerId' or the like).
I am assuming that a new customer would get an id assigned to them the minute they put something into the shopping cart, even if they are not a pre-existing customer, which invalidates my question.
I would write that the more critical issue is the synchronous invocation of GetShoppingCart during which a thread-pool thread is locked for the entire round-trip through the tiers. Under load, your scalability will be limited to "throwing hardware" at the problem.
Rewrite GetShopping cart as an asynchronous call with a timeout callback.
Also, I have a subjective dislike for "var"; it has a use in LINQ, yet when the datatype is known, I enforce the use of "int" or "string" over var(iant). Then again, I also firmly believe programming SHOULD be hard.
Nick
Comment preview
Comments have been closed on this topic.
Markdown formatting
ESC to close
Markdown turns plain text formatting into fancy HTML formatting.
Phrase Emphasis
*italic* **bold**
_italic_ __bold__
Links
Inline:
An [example](http://url.com/ "Title")
Reference-style labels (titles are optional):
An [example][id]. Then, anywhere
else in the doc, define the link:
[id]: http://example.com/ "Title"
> Email-style angle brackets
> are used for blockquotes.
> > And, they can be nested.
> #### Headers in blockquotes
>
> * You can quote a list.
> * Etc.
Horizontal Rules
Three or more dashes or asterisks:
---
* * *
- - - -
Manual Line Breaks
End a line with two or more spaces:
Roses are red,
Violets are blue.
Fenced Code Blocks
Code blocks delimited by 3 or more backticks or tildas:
```
This is a preformatted
code block
```
Header IDs
Set the id of headings with {#<id>} at end of heading line:
## My Heading {#myheading}
Tables
Fruit |Color
---------|----------
Apples |Red
Pears |Green
Bananas |Yellow
Definition Lists
Term 1
: Definition 1
Term 2
: Definition 2
Footnotes
Body text with a footnote [^1]
[^1]: Footnote text here
Abbreviations
MDD <- will have title
*[MDD]: MarkdownDeep
FUTURE POSTS
Partial writes, IO_Uring and safety - about one day from now
Configuration values & Escape hatches - 4 days from now
What happens when a sparse file allocation fails? - 6 days from now
NTFS has an emergency stash of disk space - 8 days from now
Challenge: Giving file system developer ulcer - 11 days from now
And 4 more posts are pending...
There are posts all the way to Feb 17, 2025
RECENT SERIES
Challenge
(77): 20 Jan 2025 - What does this code do?
Answer
(13): 22 Jan 2025 - What does this code do?
Comments
Remoting sux? =)
Seems it's unstable, coz there was no transaction scope used
No.
meowth,
Close, but choosing a specific technology isn't the problem.
Glueball,
Can you explain what transaction scope is important here?
If you are using read-only cart or full-serializable value-object/DTO ([d]ata [t]ransfer [o]bjects by Marinescu et al) it isn't a problem.
You are using syntactic sweet "var", so I can't know, is there any value object for cart or remotable interface. In a second case you should use access-management functionality or you can run into stale or even inconsistent data. So or better (:
Assume fully serializable DTO.
Holding remote references is something that is so wrong it didn't even occur to me.
It's hard to say given the lack of context. Perhaps you should be building up the shopping cart on the web server, and then sending it to the app server when it's ready to be processed?
I'm probably way off the mark here, but your code implies that a shopping cart will always exist for a customer.
A shopping cart is a temporal entity that exists at a certain time - in other words a customer will have multiple shopping carts in the database. Therefore this service call will have to get the current shopping cart, and if one doesn't exist, it will create it.
Having a getter service call which does a "create if not exist" is going to be a problem, especially when it comes to concurrency.
Concurrency is not an issue here, that is an implementation detail of the service.
Assume that a client can have only a single shopping cart, and that they always have it.
Hm.. seems there is nothing to say in absence of context. We are really don't know what place/layer and time this call is done at.
So probably it is an implementation issue, because I able to name when this call has no wrong direct- and side- effects =)
can i get your cart, please?
maybe because the web servers are load balanced but the app server is not?
Is customerSrv bound to a specific server instance?
The highest instability is there, if customerSrv is a pooled instance connected to a fixed server instance. This will prevent any failovers, making the call unstable.
As for the rest, by the picture and the single line of code I cannot see anything that must be unstable by the given evidence. I assume that you have put a nice try/catch/finally around it etc...
if it was assumed that a implicit cast operator have converted the remote-cart into a Cart-dto, using a var it would have not happened?
meowth,
There is sufficient context in the question. You simple cannot see the problem.
Torkel,
Assume that they are all load balanced.
Markus,
There is no catch :-)
I updated the post to show a more realistic view of a server farm, btw
chris,
The signature of the call is:
[OperationContract]
ShoppingCartDTO GetShoppingCart(int clientId);
No hidden semantics.
customerId is useless.
Really? How?
Well, this is probably wrong but it would appear that if each tier is load balanced (and we are not using some sort of sessions to ensure that calls from a client are always routed to the same machines) then subsequent calls to the GetShoppingCart method can return different carts. And multiple updates can overwrite changes that have been made to the cart.
So the instability would be a design issue rather than a implementation related side affect?
Calls to GetShoppingCart can return different versions of the same cart, yes.
And updating the cart may require reconciliation.
Still not the issue
In WCF, you need to wrap that call in try-finally block and call customerSrv.Close() in the finally. Also call customerSrv.Abort() if the customerSrv.Close() throws an exception.
Doesn't matter for the problem at hand.
Assume all book keeping is done correctly.
Don't assume that it is WCF, by the way. It was an example to make sure that you will get the idea.
WCF is a connected technology, so you can insert a sort of Service Dispatcher in your architecture in order to have for each client a "private" set of services without passing every time the customerId.
How are timeouts being handled? Or rather, what happens if the call never returns?
Tommaso,
I don't want to do that. That makes my life harder than it should.
For that matter, don't assume we are talking WCF here.
Aditya,
Ding! Ding! Ding!
You got it. I was beginning to get worried.
We have a blocking remote call here, and that is almost always a stability nightmare.
Thank you, Orin, picture started to look much better =)
So the question was - not 'invalid code', but 'unstable'?
So, you are stating that this code can become 'bad' due to special circumstances. It is left to search out those circumstances you are mentioning =)
For the first time I see that if you started to play with transaction level from serializable to at least "dirty read" on db server, you can have dirty data in DTO.
Let's start to explore further =-) Hope don't annoy you so much
Ahh i see... well now I have no idea and I am getting increasingly worried about the application I am working on which has a similar architecture!
So I'm looking forward to finding out the answer... will of course post again I think of anything! :)
meowth,
The reason that I am posting those is to show the issue and have the discussion.
I could just post my solution, but it is more interesting to have a discussion.
This is always unstable code, regardless of the circumstances.
GetShoppingCart is a method pointed to a database Stored Procedure or function, so the Database programmer can change it without assent, and the "contract" become invalid.
Am I wrong?
Orin,
thank you a lot for this question, it was really useful and interesting to ortogonate my view =)
But, I still thinking, that the problem of blocking of such type should be solved by another application logic layer (by building and configuring communication facilitites - thru AOP weaving and so on), and not directly by hi-level API - so configuration is not so perfect ;)
Any way, thank you once again.
Juliano,
God, No.
That never even occurred to me.
Note that your approach is just a derivation of the problem of failing contracts.
meowth.
My name is Oren.
It all goes back to the laws of leaky abstractions. This is not something that you can easily hide, nor do you want to.
This should be directly exposed in the UI
You wrote "no configuration mistakes". I'm not into WCF and if it's such a lousy crap that I cannot configure global timeouts, it's not worth looking at it...
So, what's the recommended way to fix the possibility of blocking? Something I thought of is the following:
Since we seem to be using a message oriented transport mechanism, we can treat each call as state in a state machine. After having made the call, we can put aside this state machine and process more messages. When we receive a message with the cart from the AppServer or the DB we proceed with whatever we were going to do to the cart. Periodically, we check to see how long any state machine is in a 'wait' state and then mark the required ones as timed out...and display a error message to the user or the like.
Hmm... surely whether to make Async calls to the service layer or not is a scalability issue rather than a stability issue? Here you are blocking worker threads meaning your app can't scale and process more requests?
Aditya,
You have just described the way Sagas works in NServiceBus :-)
Neil,
It means that a sync blocking remote call is dangerous.
It is very likely to block all your threads in such situations
Really!? Ouch - how could that be, especially in a stateless web application, can you explain? I've never experienced other threads being blocked whilst making a sync service call. Even an Async call is essentially a sync call but done in another thread or using an iocompletion port. Or are you saying we should be making duplex service calls to avoid possible problems?
I'm currently working on developing an inherited financial application and there are loads of sync calls to WCF services. So far we've had no problems but don't want them to bite us in the future! :-S
"What is wrong with this code?"
The server knows the client state. This is contrary to the Stateless REST constraint [1]
The solution: move the cart state to the client.
[1] http://roy.gbiv.com/pubs/dissertation/rest_arch_style.htm#sec_5_1_3
Alan,
How does the server know of the client state?
You can probably set the timeout using the configuration, but it doesn't really help
Oren and I have had an off-post dialogue about this. In short, I believe that he disagrees with my premise on the basis that he feels that my assumptions are wrong (not wishing to put words into his mouth).
Anyway, I thought it would be useful to post some of the links that I passed to Oren during the discussion so readers can make up their own minds.
It may make more sense when you consider that server cookies are not permitted in REST. Also note that Roy addresses the question of application state in [1] below. If you promote the cart up to being a full resource, then we are talking a different game. For a start, we are no longer looking at a traditional ecommerce platform cart implementation (if the promotion is RESTful, that is). For one thing, the cart state would have no relationship with an individual (that is to say, all people with the same cart contents would reference the same cart resource). Given that your example specifies a customerId, it doesn't seem to fit the RESTful model (it would if it took cartId instead).
"REST goes further and constrains application state (not resource state) to be held on the client. […] we can think of it as the context between user agent requests: the server cannot be aware of any such context and still be REST." Roy Fielding [1]
"Authentication is orthogonal. Cookies are also orthogonal when they are simply used for content negotiation or authentication. However, Cookie authentication is not allowed in REST because it lacks visibility, which causes security problems […]" Roy Fielding [2]
"Stateless in REST refers to the ability of the server to not know about prior requests in order to completely understand the current request." Roy Fielding [3]
"Application state in REST is what most distributed systems would call session state or transaction state, depending on which end of the system is being talked about. " Roy Fielding [4]
[1] http://tech.groups.yahoo.com/group/rest-discuss/message/3583
[2] http://tech.groups.yahoo.com/group/rest-discuss/message/3729
[3] http://tech.groups.yahoo.com/group/rest-discuss/message/4165
[4] http://tech.groups.yahoo.com/group/rest-discuss/message/10256
Alan,
In the scenario where the cart is considered a resource as well, what exactly is wrong with using the customer id to identify the cart itself? Specially given that every customer can have at most one cart. I am just trying to think what makes storing a cart id more RESTful than storing a customer id since at the end of the day, the client side will have to send a number to the server ('customerSvr/carts/customerId' or the like).
OrEn, I apologize for this mistake for Your name:/ I'm sorry.
Oren,
can't understand why you call this code unstable.
You will get TimeoutException on timeout showing that data just could not be retrieved.
This is an adequate and real-world error, isn't it?
Do you know other ways dealing with this?
See future posts to show how you will NOT get time out exceptions
What do you do in the case of new customers?
I am assuming that a new customer would get an id assigned to them the minute they put something into the shopping cart, even if they are not a pre-existing customer, which invalidates my question.
:D
I would write that the more critical issue is the synchronous invocation of GetShoppingCart during which a thread-pool thread is locked for the entire round-trip through the tiers. Under load, your scalability will be limited to "throwing hardware" at the problem.
Rewrite GetShopping cart as an asynchronous call with a timeout callback.
Also, I have a subjective dislike for "var"; it has a use in LINQ, yet when the datatype is known, I enforce the use of "int" or "string" over var(iant). Then again, I also firmly believe programming SHOULD be hard.
Nick
Comment preview