-1

I have a query to answer remote clients' standard request. Standard in the sense that it takes no params from outside the server. Whenever anyone submits a request to a URL, say http://www.example.com/query, s/he gets the contents of an reply.xml in the body of the response, depending on what the database delivers at that time. The contents of reply.xml changes only across the contents of the database on the server, and doesn't change on anything external like who does the query, on which input, etc, hence takes no params from the clients. I'm not even checking any authentication-- we're leaving everything to the firewall.

So i wrote a @POST method, say query() to get invoked on such a request posted to http://www.example.com/query, and deliver the result. I used Jersey at it and all is working fine to the specs, except that

the requests should be exclusive across time. that is, one request should be served at a time-- subsequent user-clicks should be getting a message with HTTP status 309 unless the server isn't running a query process invoked by my method query().

How to achieve this? I tried making query() serve @PUT rather than @POST responses, and got the same results.

Maybe a naive Q on the topic. However, not very familiar with Restful services.

I can do this by threading on a token to control that only one query is running at a time and make simultaneous requests receive the HTTP 309. however there must be a better, easier way to achieve this on the server.

I'm using Tomcat 8, Jersey 1.19.

TIA.

Note: I've read PUT vs POST in REST among some other useful discussions.

//=====================

EDIT:

Which user submits the quer doesn't make any difference at any time.

Suppose userA submitted a query. while that query is still running, i.e., before query() returns the response to userA, userB submitted a query. userB should be getting a 309-- just because there's a query being processed at the time.

Whether userA = userB or userA <> userB is immaterial here, a 309 should be returned just because there's a query request while one is already running. and thats the only time a user gets a 309.

//==============================================

EDIT-2:

I'm aware of solutions w/concurrency control. I'm guessing that there is one using the Restful features. this is rather an academic Q.

Community
  • 1
  • 1
Roam
  • 4,831
  • 9
  • 43
  • 72
  • You want queries to be 309 for different users or for the same user running the query again? – RealSkeptic Aug 20 '16 at 18:40
  • @RealSkeptic doesn't matter whether it's the same/different user. pls see my edit in the Q. – Roam Aug 20 '16 at 18:48
  • maybe http://stackoverflow.com/questions/8775079/how-to-rate-limit-an-api –  Aug 20 '16 at 18:50
  • Well, if they are running in the same JVM, you can use a ReentrantLock, I suppose. – RealSkeptic Aug 20 '16 at 18:50
  • @RC rate won't matter. we're not supposed to restrict it. the only thing we should avoid is the simultaneous ones as I stated in the Q. – Roam Aug 20 '16 at 18:55
  • I don't know if there's anything in the HTTP spec to disallow that, that's up to the server to implement (and hence, REST). It's not that strange, since http 309 is undefined (and http 3xx means redirect), see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml So the code to send http 309 is to be implemented by the servlet, not by the container. However, even a quick google: http://stackoverflow.com/questions/131681/how-can-i-implement-rate-limiting-with-apache-requests-per-second might do the trick, but I'm not well versed in that... – Koos Gadellaa Aug 20 '16 at 19:47
  • @stdunbar too bad you didn't see that earlier. would've saved you the unnecessary answer. – Roam Aug 20 '16 at 20:47

2 Answers2

2
  • @Koos Gadellaa is correct in saying the client should be blocking the second request until the response arrives. Let me expound on why this is the best thing to do. Architecturally, it relates to concerns. The server does not have context awareness as to why two requests have arrived in parallel. Therefore, it is relying on out-of-band knowledge to know parallel requests are bad. Any out-of-band knowledge creates a coupling, meaning if you change how one part of the system works, you have to change the other. RESTful architectures are popular because they reduce coupling. If the same user is logged into two clients then the system breaks. You never want to build systems with this type of client-server coupling.

  • Regarding the server's responsibility, good coding practices come into play, the best thing to do would be to ensure the service is not impeded by multiple parallel requests from the user. Caching may be your friend. Based on query parameters, the response could be written to a cache file on disk. The client would always be redirected with HTTP 303 to the cache file URL. 304 Not Modified could be used so the client would not have to download the answer twice. In this scenario, the only out-of-band knowledge is proper implementation of the HTTP spec which is well specified and robust.

  • The appropriate response code seems to be 503 if the service is overloaded.

    10.5.4 503 Service Unavailable

    The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response.

         Note: The existence of the 503 status code does not imply that a
         server must use it when becoming overloaded. Some servers may wish
         to simply refuse the connection.
    
  • Since you directed me here from my response here, it would appear you want to know the correct RESTful approach. This will be more complex than the solutions above and my guess would be you don't want to take this route but here it is.

    If the server needs to communicate to the client that a request is being performed and when it completes, then resources need to be created for those concepts. This feels weird because they concepts exist in HTTP and it is odd to reimplement them at a higher level (architectural smell).

    1. The client would POST a Request or Query resource to the server. This resource would have a Response property that is empty and a Status property which is empty. The server would respond with a body that has the Status property set to "processing".
    2. The client would then perform GETs to this resource (possibly use long-polling here) to check for updates.
    3. When the response has been created, the Response property would then link to a response resource or have the response embedded.

    This approach communicates what is happening using resources. Therefore, the only out-of-band knowledge is the valid states of the resource.

Community
  • 1
  • 1
Joshcodes
  • 8,513
  • 5
  • 40
  • 47
0

I think you're framing it wrong. A user clicking multiple times is a user using the frontend client to connect to your server. Hence, it is up to the client to ensure that no multiple clicks occur. Javascript can perfectly fend off such requests.

Having said that, onto your request: the fact that a 309 should be returned. This is a concurrency problem.
If I read your specs correctly, it is related to a database query being performed. Consider the following code:

result = do_database_thing();
out = make_up_result(result);
return out;

As per these specs, the only request is that the critical section is on the do_database_thing. If make_up_results is slow, multiple requests are allowed. So the natural solution is to use locking on the database. If it should encompass the entire query() method (i.e. not the database query itself), request the lock early, release the lock at the end. Then the code becomes:

boolean locked = get_lock();
if(!locked) return 302;
result = do_database_thing();
release_lock();
out = make_up_result(result);
return out;
Koos Gadellaa
  • 1,220
  • 7
  • 17
  • you're making assumptions on the specs. don't. – Roam Aug 20 '16 at 19:25
  • the client can submit the query whichever the way s/he wants. it's up to them. the url might just be sitting o two browsers simultaneously clicked. or one applications sending requests one after the other just for the heck of it. and our concern isn't one of consistency of the results out of the DB. – Roam Aug 20 '16 at 19:27
  • Well.... locks are not (directly) used to prevent consistency to the database, they are to prevent access from multiple sources to a single shared resource. When you have single access to a shared resource, any updates you do are (usually) consistent, so it's a result of having that single access, which is in turn guaranteed by locks. And that is why I'd suggest a lock in this case: to guarantee single access. Not to update, or consistency, but just as a special token, available on the resource to be accessed exclusively, managed on that resource, and verified on that resource. – Koos Gadellaa Aug 20 '16 at 19:43
  • well .. more to it than making a case for your answer. don't need to concern db for the sake of lock not to mention te bad practice. – Roam Aug 20 '16 at 20:49