9

Context

Due to the statelessness of the REST architectural style involving that each requests stands completely alone, leading server to never store any informations about client.

Thus, pessimistic concurrency control are not suitable because it would requires that server store which client gets the lock on a resource. Optimistic concurrency control are then used, with the help of Etag header. (btw, as I asked there https://stackoverflow.com/questions/30080634/concurrency-in-a-rest-api)

Problem

The main problem with an optimistic concurrency control mechanism is that you allow all the time, all clients, to perform any operations.

And i would like to avoid that without breaking the statelessness principle of REST. I mean that all clients cannot perform any operation at any time.

Question

In my mind, it would possible with a semi-optimistic concurrency control mechanism, like that:

  • Clients can request a token
  • Only one token can be generated and has a limited period of validity
  • To perform operations on resources (such as POST or PUT), client must give this token as part of the body (or header?) of the request. Client that don't have the token cannot do these operations.

It is very similar to optimistic concurrency control, except that only one client can do some operations (the one that got the token)... at the opposite of "all clients can do all operations".

Does this mechanism is compatible with a REST architectural style ? Does it break any of its constraint ? I was thinking to ask on SO, but this seems more an high-level question, related to software design.

  • It's rather simple, actually: you have to model a Transaction explicitly as a Resource. – Jörg W Mittag Jun 23 '15 at 14:09
  • What does it changes ? Not sure to understand your comment. I am not doing concurrency control for transaction, but rather for saying to client "ok now, you are absolutely sure that no one would change the resource" (as it got a unique token). – AilurusFulgens Jun 23 '15 at 14:35
  • 1
    What is the difference? On the one side, you use the Etag to check, who is allowed to update the "current" version; if it clashes, you have to update your version and do the update after that. On the other side, you have your "locking" mechanism: one is allowed, others have to wait. Sounds pretty the same. The downside to the second approach: 2 requests - 1 for the lock and 1 for the update. In an optimal case, you have only one update via the Etag-approach. – Thomas Junk Jun 23 '15 at 14:39
  • Well, generally speaking about concurrency control... the second that "lost the race" will always have to wait (just for different reasons, i agree with that). Difference with Etag ? With Etag you are never sure that your operations will be complete, you could have a situation where you will never never perform any operations. With a lock, you are sure at least to perform your operation. So having a simple lock is just a middle between an environment where "high conflicts" and "rare conflicts" can happen. – AilurusFulgens Jun 23 '15 at 15:04
3

You should never ( as in never ever EVER) lock any resource while waiting for a user interaction.

At some point some of your users will take off for a long weekend leaving some vital records locked.

Ah but you won't let that happen because you have some clever time out/deadlock resolution scheme; then at some point this will go horribly wrong and a user who got a nice "your widget has been ordered" message will be screaming at the help desk demanding to know why his widget was not delivered.

Most people can deal with "sorry another user has just ordered this part" message.

  • You explained it nicely. Although i am not completely convinced by your first sentence: at some point you would guarantee that nobody else than you can perform an order. But well, your last sentence is a good summary, in 99% of the time it is the case. – AilurusFulgens Jul 8 '15 at 21:38
  • 1
    If you need to lock a record for a particular user then do it at the application level. Either will a simple "LockedBy" attribute, or, with some more sophisticated versioning and workflow mechanism. – James Anderson Jul 9 '15 at 7:01
  • What do you mean by "at the application level" ? If you add a "LockedBy" attribute on your resource, then you store information about client on your server. Or maybe i didn't understood your comment. If you can provide some details it would be great! – AilurusFulgens Jul 10 '15 at 21:42
  • 1
    @AilurusFulgens -- You add a LockedBy attribute (and possibly a LockedOn timestamp) to your database. In your application code you set the user name and time whenever the client starts an update interaction. You unset it when the client is finished -- you then need to work out some business rules to resolve conflicts and timeouts etc. – James Anderson Jul 11 '15 at 8:13
2

Using tokens is very common in APIs, these tokens are usually sent as a header and have a clear life cycle. Think for instance OAuth.

Regardless of your programming language or framework, REST APIs are similar.

I can think of several scenarios where you want to limit concurrency, two of them are:

  1. Multiple clients updating the same resources like a database row. For instance: two concurrent requests, one deletes a record and the other one tries to update the same record. Depending on your database and how you have set it up, you might get a lock on the records or invalid operation since the data will be different or will not exist.

  2. A super user or administrator performing special actions with the API.


What to do in these cases?

  1. Use transactions in the database, singletons, locks and similar mechanisms to synchronize the access to the resources.

  2. The token might work, I think it will be better if you don't store information about the client, just about the token itself. On one step you could validate the user and assign the token. Then just validate that the token is alive and is valid. Use a token that can be decrypted to obtain extra information. You can store if this is an special token and allow only on at a time. This way you validate the token, not the user.

I hope this helps.

  • Yes, i was expecting a response about the similiarity of a token and the OAuth mechanism. Although the last one is dedicated to authentication. I didn't get the point of your scenario 1. The tricky part to deal with concurrency in a REST API is to keep the statelessness constraint... meaning that the server doesn't store information about client. Your scenario 2 is exactly what i'm doing currently! :) – AilurusFulgens Jul 7 '15 at 10:30
  • Did I answer your question? – Pablo Granados Jul 8 '15 at 20:41
  • No sorry. I upvoted your answer because it gives a good overview of the problem but unfortunately, imo, it is not really tackling it. – AilurusFulgens Jul 8 '15 at 21:40
0

REST alone is too primitive, really. You can get started with REST, but eventually, your rich application will need queries with joins and updates with transactions. Every developer attempting to add these things on their own would be error prone and inconsistent. Fortunately, there's an emerging standard called OData that does just that. It layers on top of REST and provides (1) query language that allows for simple joins using navigational properties (without having to expose foreign keys), and, (2) batch processing that includes atomic change sets.

See here for (1) https://stackoverflow.com/a/3921423/471129 , and,

See here and for (2) https://stackoverflow.com/a/21939972/471129

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.