Oren Eini

aka Ayende Rahien

Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,575
|
Comments: 51,189

Copyright ©️ Ayende Rahien 2004 — 2025

Privacy Policy · Terms
filter by tags archive
stack view grid view
  • architecture (606) rss
  • bugs (450) rss
  • challanges (123) rss
  • community (377) rss
  • databases (481) rss
  • design (893) rss
  • development (640) rss
  • hibernating-practices (71) rss
  • miscellaneous (592) rss
  • performance (397) rss
  • programming (1085) rss
  • raven (1442) rss
  • ravendb.net (526) rss
  • reviews (184) rss
  • 2025
    • May (7)
    • April (10)
    • March (10)
    • February (7)
    • January (12)
  • 2024
    • December (3)
    • November (2)
    • October (1)
    • September (3)
    • August (5)
    • July (10)
    • June (4)
    • May (6)
    • April (2)
    • March (8)
    • February (2)
    • January (14)
  • 2023
    • December (4)
    • October (4)
    • September (6)
    • August (12)
    • July (5)
    • June (15)
    • May (3)
    • April (11)
    • March (5)
    • February (5)
    • January (8)
  • 2022
    • December (5)
    • November (7)
    • October (7)
    • September (9)
    • August (10)
    • July (15)
    • June (12)
    • May (9)
    • April (14)
    • March (15)
    • February (13)
    • January (16)
  • 2021
    • December (23)
    • November (20)
    • October (16)
    • September (6)
    • August (16)
    • July (11)
    • June (16)
    • May (4)
    • April (10)
    • March (11)
    • February (15)
    • January (14)
  • 2020
    • December (10)
    • November (13)
    • October (15)
    • September (6)
    • August (9)
    • July (9)
    • June (17)
    • May (15)
    • April (14)
    • March (21)
    • February (16)
    • January (13)
  • 2019
    • December (17)
    • November (14)
    • October (16)
    • September (10)
    • August (8)
    • July (16)
    • June (11)
    • May (13)
    • April (18)
    • March (12)
    • February (19)
    • January (23)
  • 2018
    • December (15)
    • November (14)
    • October (19)
    • September (18)
    • August (23)
    • July (20)
    • June (20)
    • May (23)
    • April (15)
    • March (23)
    • February (19)
    • January (23)
  • 2017
    • December (21)
    • November (24)
    • October (22)
    • September (21)
    • August (23)
    • July (21)
    • June (24)
    • May (21)
    • April (21)
    • March (23)
    • February (20)
    • January (23)
  • 2016
    • December (17)
    • November (18)
    • October (22)
    • September (18)
    • August (23)
    • July (22)
    • June (17)
    • May (24)
    • April (16)
    • March (16)
    • February (21)
    • January (21)
  • 2015
    • December (5)
    • November (10)
    • October (9)
    • September (17)
    • August (20)
    • July (17)
    • June (4)
    • May (12)
    • April (9)
    • March (8)
    • February (25)
    • January (17)
  • 2014
    • December (22)
    • November (19)
    • October (21)
    • September (37)
    • August (24)
    • July (23)
    • June (13)
    • May (19)
    • April (24)
    • March (23)
    • February (21)
    • January (24)
  • 2013
    • December (23)
    • November (29)
    • October (27)
    • September (26)
    • August (24)
    • July (24)
    • June (23)
    • May (25)
    • April (26)
    • March (24)
    • February (24)
    • January (21)
  • 2012
    • December (19)
    • November (22)
    • October (27)
    • September (24)
    • August (30)
    • July (23)
    • June (25)
    • May (23)
    • April (25)
    • March (25)
    • February (28)
    • January (24)
  • 2011
    • December (17)
    • November (14)
    • October (24)
    • September (28)
    • August (27)
    • July (30)
    • June (19)
    • May (16)
    • April (30)
    • March (23)
    • February (11)
    • January (26)
  • 2010
    • December (29)
    • November (28)
    • October (35)
    • September (33)
    • August (44)
    • July (17)
    • June (20)
    • May (53)
    • April (29)
    • March (35)
    • February (33)
    • January (36)
  • 2009
    • December (37)
    • November (35)
    • October (53)
    • September (60)
    • August (66)
    • July (29)
    • June (24)
    • May (52)
    • April (63)
    • March (35)
    • February (53)
    • January (50)
  • 2008
    • December (58)
    • November (65)
    • October (46)
    • September (48)
    • August (96)
    • July (87)
    • June (45)
    • May (51)
    • April (52)
    • March (70)
    • February (43)
    • January (49)
  • 2007
    • December (100)
    • November (52)
    • October (109)
    • September (68)
    • August (80)
    • July (56)
    • June (150)
    • May (115)
    • April (73)
    • March (124)
    • February (102)
    • January (68)
  • 2006
    • December (95)
    • November (53)
    • October (120)
    • September (57)
    • August (88)
    • July (54)
    • June (103)
    • May (89)
    • April (84)
    • March (143)
    • February (78)
    • January (64)
  • 2005
    • December (70)
    • November (97)
    • October (91)
    • September (61)
    • August (74)
    • July (92)
    • June (100)
    • May (53)
    • April (42)
    • March (41)
    • February (84)
    • January (31)
  • 2004
    • December (49)
    • November (26)
    • October (26)
    • September (6)
    • April (10)
RavenDB - High-Performance NoSQL Document Database
  previous post next post  
Jul 21 2008

Unstable code

time to read 1 min | 47 words

This is part of a presentation that I am currently preparing, can you tell me what is wrong with this code?

image

There is no catch, no configuration mistakes, no implementation semantics that are not shown here.

Tweet Share Share 52 comments
Tags:
  • Bugs

  previous post next post  

Comments

meowth
21 Jul 2008
11:17 AM
meowth

Remoting sux? =)

glueball
21 Jul 2008
11:20 AM
glueball

Seems it's unstable, coz there was no transaction scope used

James L
21 Jul 2008
11:25 AM
James L

No.

Ayende Rahien
21 Jul 2008
11:25 AM
Ayende Rahien

meowth,

Close, but choosing a specific technology isn't the problem.

Ayende Rahien
21 Jul 2008
11:26 AM
Ayende Rahien

Glueball,

Can you explain what transaction scope is important here?

glueball
21 Jul 2008
11:38 AM
glueball

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 (:

Ayende Rahien
21 Jul 2008
11:44 AM
Ayende Rahien

Assume fully serializable DTO.

Holding remote references is something that is so wrong it didn't even occur to me.

Neil Mosafi
21 Jul 2008
11:55 AM
Neil Mosafi

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?

Neil Mosafi
21 Jul 2008
12:18 PM
Neil Mosafi

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.

Ayende Rahien
21 Jul 2008
12:21 PM
Ayende Rahien

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.

meowth
21 Jul 2008
12:44 PM
meowth

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

c.sokun
21 Jul 2008
12:55 PM
c.sokun

can i get your cart, please?

Torkel
21 Jul 2008
12:57 PM
Torkel

maybe because the web servers are load balanced but the app server is not?

Markus Zywitza
21 Jul 2008
12:58 PM
Markus Zywitza

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...

chris
21 Jul 2008
12:58 PM
chris

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?

Ayende Rahien
21 Jul 2008
13:01 PM
Ayende Rahien

meowth,

There is sufficient context in the question. You simple cannot see the problem.

Ayende Rahien
21 Jul 2008
13:02 PM
Ayende Rahien

Torkel,

Assume that they are all load balanced.

Ayende Rahien
21 Jul 2008
13:07 PM
Ayende Rahien

Markus,

There is no catch :-)

I updated the post to show a more realistic view of a server farm, btw

Ayende Rahien
21 Jul 2008
13:08 PM
Ayende Rahien

chris,

The signature of the call is:

[OperationContract]

ShoppingCartDTO GetShoppingCart(int clientId);

No hidden semantics.

Tommaso Caldarola
21 Jul 2008
13:09 PM
Tommaso Caldarola

customerId is useless.

Ayende Rahien
21 Jul 2008
13:12 PM
Ayende Rahien

Really? How?

Aditya Caprihan
21 Jul 2008
13:22 PM
Aditya Caprihan

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?

Ayende Rahien
21 Jul 2008
13:24 PM
Ayende Rahien

Calls to GetShoppingCart can return different versions of the same cart, yes.

And updating the cart may require reconciliation.

Still not the issue

Neil Mosafi
21 Jul 2008
13:28 PM
Neil Mosafi

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.

Ayende Rahien
21 Jul 2008
13:31 PM
Ayende Rahien

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.

Tommaso Caldarola
21 Jul 2008
13:33 PM
Tommaso Caldarola

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.

Aditya Caprihan
21 Jul 2008
13:34 PM
Aditya Caprihan

How are timeouts being handled? Or rather, what happens if the call never returns?

Ayende Rahien
21 Jul 2008
13:35 PM
Ayende Rahien

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.

Ayende Rahien
21 Jul 2008
13:37 PM
Ayende Rahien

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.

meowth
21 Jul 2008
13:37 PM
meowth

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

Neil Mosafi
21 Jul 2008
13:37 PM
Neil Mosafi

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! :)

Ayende Rahien
21 Jul 2008
13:38 PM
Ayende Rahien

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.

Juliano Nunes
21 Jul 2008
13:44 PM
Juliano Nunes

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?

meowth
21 Jul 2008
13:45 PM
meowth

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.

Ayende Rahien
21 Jul 2008
13:47 PM
Ayende Rahien

Juliano,

God, No.

That never even occurred to me.

Note that your approach is just a derivation of the problem of failing contracts.

Ayende Rahien
21 Jul 2008
13:48 PM
Ayende Rahien

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

Markus Zywitza
21 Jul 2008
13:53 PM
Markus Zywitza

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...

Aditya Caprihan
21 Jul 2008
13:58 PM
Aditya Caprihan

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.

Neil Mosafi
21 Jul 2008
14:00 PM
Neil Mosafi

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?

Ayende Rahien
21 Jul 2008
15:36 PM
Ayende Rahien

Aditya,

You have just described the way Sagas works in NServiceBus :-)

Ayende Rahien
21 Jul 2008
15:37 PM
Ayende Rahien

Neil,

It means that a sync blocking remote call is dangerous.

It is very likely to block all your threads in such situations

Neil Mosafi
21 Jul 2008
16:07 PM
Neil Mosafi

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

Alan Dean
21 Jul 2008
16:16 PM
Alan Dean

"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

Ayende Rahien
21 Jul 2008
16:32 PM
Ayende Rahien

Alan,

How does the server know of the client state?

Ayende Rahien
21 Jul 2008
19:00 PM
Ayende Rahien

You can probably set the timeout using the configuration, but it doesn't really help

Alan Dean
21 Jul 2008
20:15 PM
Alan Dean

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

Aditya Caprihan
22 Jul 2008
00:46 AM
Aditya Caprihan

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

meowth
22 Jul 2008
06:15 AM
meowth

OrEn, I apologize for this mistake for Your name:/ I'm sorry.

Konstantin Spirin
22 Jul 2008
10:09 AM
Konstantin Spirin

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?

Ayende Rahien
22 Jul 2008
10:40 AM
Ayende Rahien

See future posts to show how you will NOT get time out exceptions

Robz
22 Jul 2008
20:31 PM
Robz

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

Nicholas de Lioncourt
06 Aug 2008
12:00 PM
Nicholas de Lioncourt

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"

Images

Inline (titles are optional):

![alt text](/path/img.jpg "Title")

Reference-style:

![alt text][id]
[id]: /url/to/img.jpg "Title"

Headers

Setext-style:

Header 1
========
Header 2
--------

atx-style (closing #'s are optional):

# Header 1 #
## Header 2 ##
###### Header 6

Lists

Ordered, without paragraphs:

1.  Foo
2.  Bar

Unordered, with paragraphs:

*   A list item.
    With multiple paragraphs.
*   Bar

You can nest them:

*   Abacus
    * answer
*   Bubbles
    1.  bunk
    2.  bupkis
        * BELITTLER
    3. burper
*   Cunning

Blockquotes

> 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

  1. NOT Sharding RavenDB Vector Search - 7 hours from now
  2. Optimizing the cost of clearing a set - 3 days from now
  3. Scaling HNSW in RavenDB: Optimizing for inadequate hardware - 5 days from now

There are posts all the way to May 14, 2025

RECENT SERIES

  1. RavenDB News (2):
    02 May 2025 - May 2025
  2. Recording (15):
    30 Apr 2025 - Practical AI Integration with RavenDB
  3. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
  4. RavenDB (13):
    02 Apr 2025 - .NET Aspire integration
  5. RavenDB 7.1 (6):
    18 Mar 2025 - One IO Ring to rule them all
View all series

RECENT COMMENTS

  • ถูกใจ ร้านนี้สุดๆ! อุปกรณ์ จาก inkspa pantip ทำให้ ผลงาน สวย จ้าง เสื้อ ทีม ได้ งาน ลงตัว ราคา คุ้ม ชวน ใคร อยากได้ ดีไซน...
    By ink-spa พันทิป on The null check that didn't check for nulls
  • But in case you have nullability checks enabled (i.e. `<Nullable>enable</Nullable>`), then you'll have a compiler warning on ...
    By Samyon Ristov on The null check that didn't check for nulls
  • Grok wasn't *wrong*. It only said that `_items` can't be null for the condition to evaluate to `true`, but didn't say anythi...
    By Johannes Egger on The null check that didn't check for nulls
  • When I started enabling NRT, I remember I was initially confused when all variables (for reference types) declared with `var`...
    By riccardo on The null check that didn't check for nulls
  • That is surprising - I think of var as a shorthand that does not affect the final result of the compilation. I wouldn't expec...
    By Chris B on The null check that didn't check for nulls

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}