Concurrent requests

42 views
Skip to first unread message

Łukasz Lewczyński

unread,
Sep 15, 2017, 6:29:15 AM9/15/17
to OpenLMIS Dev
Hi all,

I was looking why sometimes on the Malawi production server users see duplicate LMIS form comments and I found out it is possible to send several requests (in the same) to change a requisition status and all of them will be executed properly.

In other words, in the database there will be several entries in the requisition.status_changes table and if there was draft of comment in the form then there will be several entries in the requisition.status_messages table.

I think the problem is more general because we don't have any mechanism to control concurrent requests. Basically If a user sends several requests at the same time, with the same data, an endpoint will work normally and all our validations will be omitted because data in the database and in the requests are correct.

It was hard for me to find any useful information about how to handle this issue. One solution was about using 412 HTTP error code and If-Unmodified-Since header. But in our case it will be still possible to send several requests with the same If-Unmodified-Since header but it probably removes problem with double click on the UI. Other solution was to somehow lock a resource that is required by the request. In this situation only one of requests could make changes and another requests will have to wait or they will be rejected.

What do you think about that? Do you know any other good solution to avoid this problem?

Regards,
Lukasz

Łukasz Lewczyński
Software Developer
llewc...@soldevelo.com


SolDevelo
Sp. z o.o. [LLC] / www.soldevelo.com
Al. Zwycięstwa 96/98, 81-451, Gdynia, Poland
Phone: +48 58 782 45 40 / Fax: +48 58 782 45 41

Brandon Bowersox-Johnson

unread,
Sep 15, 2017, 3:41:26 PM9/15/17
to Łukasz Lewczyński, OpenLMIS Dev

I don't think OpenLMIS has established a pattern for this yet.

 

Browser-side options could involve putting in logic to prevent or handle the AngularJS app making multiple concurrent requests to the same API in certain cases like this. For example, when the app is saving/updating a Requisition, perhaps we need a loading spinner on screen so we prevent the user from clicking any button a second time and causing a concurrent request. That may be the easiest option. Similar approaches in the AngularJS service layer could use a locking mechanism or queue mechanism.

 

Server-side options are more robust/reliable, especially in situations where we have browsers with inconsistent internet connectivity. This could involve a token that the server checks as well as the If-Unmodified-Since header. Here is a good article about REST Best Practices for Managing Concurrent Updates: https://blog.4psa.com/rest-best-practices-managing-concurrent-updates/ . It includes the solution Łukasz is describing.

 

-Brandon

--
You received this message because you are subscribed to the Google Groups "OpenLMIS Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openlmis-dev...@googlegroups.com.
To post to this group, send email to openlm...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openlmis-dev/CAAdp53yBV3Jn%2Bcvv%3DUSd54cR6Fv%3D3qJUOc9M1HmNtvU%3DmMLqMg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Nikodem Graczewski

unread,
Sep 18, 2017, 2:13:34 AM9/18/17
to OpenLMIS Dev
Putting this responsibility on the UI side is kind of doomed to fail in my opinion. We already have a spinner when saving/updating Requisitions and the user can always just press F5 and start again. I agree that the server-side options are more reliable and using one of them should be the road we take.

Łukasz Lewczyński

unread,
Sep 18, 2017, 6:49:40 AM9/18/17
to Nikodem Graczewski, OpenLMIS Dev
I think the solution to this problem should be on the server side. When I checked how the server will handle concurrent requests I used bash terminal instead of UI. Also we get from time to time informations that during save/submit a requisition on UI adjustments are duplicated and because of that it is impossible to authorize the requisition without changing the form - by removing those duplicates. We captured a requisition that have duplicated adjustments and I noticed that this requisition has duplicates in the status_changes table so I think this issue is related with concurrent requests.


Łukasz Lewczyński
Software Developer
llewc...@soldevelo.com

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

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

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

Łukasz Lewczyński

unread,
Sep 22, 2017, 6:05:35 AM9/22/17
to Nikodem Graczewski, OpenLMIS Dev
Hi again,

I created a ticket in the core space: https://openlmis.atlassian.net/browse/OLMIS-3235

Regards,
Lukasz


Łukasz Lewczyński
Software Developer
llewc...@soldevelo.com

Sebastian Brudziński

unread,
Sep 25, 2017, 8:43:44 AM9/25/17
to openlm...@googlegroups.com

I agree that this should be fixed on the server side. No matter what we do on the UI, it will always be possible to send multiple requests (even because users can have rights to the exact same requisition and they may decide to submit at the same time).

What Brandon's article is describing is a little different than the problem we are having in Malawi. Moreover, we already have a similar fix implemented manually for the save operation (returning 409 Conflict in case the update dates do not match, which prevents overwriting someone's changes). The problem is when the submit, authorize or other requests are sent at the very same time. Since submit and authorize can be lengthy (several seconds), it is possible to have the validation pass for both of the concurrent requests, before the changes are saved into the database. Simplified workflow would look like:
(validation including conflict check) -> (other logic / several seconds of processing) -> (save to the database)
It is therefore possible to have two or more requests pass the validation, then be "stuck" for a few seconds on processing the request and then flush everything to the database (where each request that passed validation would do so and therefore potentially create duplicate entries like comments or status changes). The problem is therefore with those couple of seconds between validation and the flush to the database.

I think there are two mistakes that we have made:
 - Not relying on built-in locking of the resources (would need to explore what Spring Data offers and how it handles that)
 - Not including those checks for operations other than save

A potential solution would be to refactor those checks to locks on the database level. We would need to explore what Spring offers and how to best tackle it first. We would want to lock a specific resource only (eq. requisition with id xyz). That means I can still concurrently update 5 different requisitions, but if I try to do it with the same requisition, I wouldn't be able to do so. Another question that needs to be answered is whether we would want optimistic or pessimistic locking. Do we just allow everything and throw an exception if conflict is detected? Or do we not allow concurrent processing of the same resource (waiting for the lock)? The latter may be more problematic on the database level.

Alternative approach would be to keep those checks manual but refactor them to be resource locks. Submitting requisition xyz would create a lock on xyz and no other resource update would be allowed to proceed for requisition xyz until the submit of xyz is done. This would involve keeping track of the locks (eg. by requisition id) and supporting timeouts (if resource wasn't unlocked after x minutes, the lock is released).

It would be great to get more opinions/voices on this. Concurrent requests causing duplicate comments/status changes are quite a big issue for Malawi, so having a plan to tackle this is important for us. Why the UI allows users to send concurrent requests (we have vefrified that most cases of concurrent requests are not multiple users operating on the same resource, but a single user sending multiple requests) is another case and we are investigating that in a separate ticket. Nevertheless, the API should be capable of handling the concurrent requests on its own as well, for the reasons mentioned above.

Best regards,
Sebastian.

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

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

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

--

Sebastian Brudziński
Software Developer / Team Leader
sbrud...@soldevelo.com

Nick Reid

unread,
Sep 25, 2017, 11:50:49 AM9/25/17
to Sebastian Brudziński, openlm...@googlegroups.com

Sebastian, thanks for keeping this thread going and getting more input


You mentioned we are getting errors from MW — has anyone started collecting and summarizing these errors? It would be great to have a concrete section to look at, improve, and document a "best practice" around.


I do agree that the ultimate solution is to fix the issue on the backend, because I know we want to support multiple clients (eventually) — that might be written with out any of our knowledge.


On the UI side, I think we could up our game a little. A goal we need to build metrics around (and then fix) is the number of HTTP requests the UI makes, as that directly relates to a good UX and operating cost for Malawi (and other places we work)


I have noticed code that doesn't really follow an OO pattern, which would make "locking" objects easier to work with — and I could go "splunking" for specifics, but would much rather have analytics to guide where we do refactors.


-- nick --


Nick Reid | nick...@villagereach.org
Software Developer, Information Systems Group


VillageReach Starting at the Last Mile
2900 Eastlake Ave. E, Suite 230, Seattle, WA 98102, USA
CELL: +1.510.410.0020
SKYPE: nickdotreid
www.villagereach.org



From: openlm...@googlegroups.com <openlm...@googlegroups.com> on behalf of Sebastian Brudziński <sbrud...@soldevelo.com>
Sent: Monday, September 25, 2017 5:43:40 AM
To: openlm...@googlegroups.com
Subject: Re: [openlmis-dev] Re: Concurrent requests
 

Sebastian Brudziński

unread,
Sep 26, 2017, 4:58:36 AM9/26/17
to Nick Reid, openlm...@googlegroups.com

Thanks for your input, Nick. I've started a simple Confluence page on the Malawi space that sums up the current issues caused by concurrent requests and possible causes of concurrent requests coming from the same user: https://openlmis.atlassian.net/wiki/spaces/MW/pages/116031617/Concurrency+issues


Best regards,
Sebastian.

Paweł Gesek

unread,
Sep 26, 2017, 5:51:55 AM9/26/17
to Sebastian Brudziński, Nick Reid, openlm...@googlegroups.com
Ideally the database should force the data integrity. Locking solutions in services will be hard to scale.

Perhaps we are missing some form of a constraint on our audit entries/comments?

If it's a bit more complex than that, there are also ways to prevent this on the database level (triggers, check constraints, procedures) that we can consider.

Regards,
Paweł

On Tue, Sep 26, 2017 at 10:58 AM, Sebastian Brudziński <sbrud...@soldevelo.com> wrote:

Thanks for your input, Nick. I've started a simple Confluence page on the Malawi space that sums up the current issues caused by concurrent requests and possible causes of concurrent requests coming from the same user: https://openlmis.atlassian.net/wiki/spaces/MW/pages/116031617/Concurrency+issues


Best regards,
Sebastian.


On 25.09.2017 17:50, Nick Reid wrote:

Sebastian, thanks for keeping this thread going and getting more input


You mentioned we are getting errors from MW — has anyone started collecting and summarizing these errors? It would be great to have a concrete section to look at, improve, and document a "best practice" around.


I do agree that the ultimate solution is to fix the issue on the backend, because I know we want to support multiple clients (eventually) — that might be written with out any of our knowledge.


On the UI side, I think we could up our game a little. A goal we need to build metrics around (and then fix) is the number of HTTP requests the UI makes, as that directly relates to a good UX and operating cost for Malawi (and other places we work)


I have noticed code that doesn't really follow an OO pattern, which would make "locking" objects easier to work with — and I could go "splunking" for specifics, but would much rather have analytics to guide where we do refactors.


-- nick --


Software Developer, Information Systems Group


VillageReach Starting at the Last Mile
2900 Eastlake Ave. E, Suite 230, Seattle, WA 98102, USA
CELL: +1.510.410.0020
SKYPE: nickdotreid
www.villagereach.org



--

Sebastian Brudziński
Software Developer / Team Leader
sbrud...@soldevelo.com



SolDevelo
Sp. z o.o. [LLC] / www.soldevelo.com
Al. Zwycięstwa 96/98, 81-451, Gdynia, Poland
Phone: +48 58 782 45 40 / Fax: +48 58 782 45 41

--
You received this message because you are subscribed to the Google Groups "OpenLMIS Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openlmis-dev+unsubscribe@googlegroups.com.
To post to this group, send email to openlm...@googlegroups.com.

--

Sebastian Brudziński
Software Developer / Team Leader
sbrud...@soldevelo.com



SolDevelo
Sp. z o.o. [LLC] / www.soldevelo.com
Al. Zwycięstwa 96/98, 81-451, Gdynia, Poland
Phone: +48 58 782 45 40 / Fax: +48 58 782 45 41

--
You received this message because you are subscribed to the Google Groups "OpenLMIS Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openlmis-dev+unsubscribe@googlegroups.com.
To post to this group, send email to openlm...@googlegroups.com.

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



--

Paweł Gesek
Technical Project Manager
pge...@soldevelo.com / +48 690 020 875

Sebastian Brudziński

unread,
Sep 26, 2017, 7:08:47 AM9/26/17
to Paweł Gesek, Nick Reid, openlm...@googlegroups.com

Finding a unique constraint for comments / audit entries may be difficult as we should allow identical comments and requisitions reaching the same status (eg. after being rejected). The timestamps usually won't be the same either.

While we need the database to force its integrity, I don't believe this is an ultimate solution to the concurrency issues. Saving a requisition may serve as an example. It doesn't produce a new resource and so simply enforcing it's unique doesn't give us much here.

What kind of triggers or procedures to prevent concurrency do you have in mind exactly?

Regards,
Sebastian.

Nick Reid

unread,
Oct 2, 2017, 2:50:45 PM10/2/17
to Brandon Bowersox-Johnson, Łukasz Lewczyński, OpenLMIS Dev

Speaking to the browser side, I think incorporating a separation between the object being saved, and the resource/service doing the saving would be quick to prevent this from happening going forward


Here is a code sample with what we would want to adopt -- you will notice that the user object knows if it has a request in progress, and instead of making a new request -- it passes back the promise for the original request.


I was going to implement this into a couple of referencedata services today -- but we will need to figure out how to prioritize this work, since it makes no sense to go backwards and update everything right now


-- nick --


Nick Reid | nick...@villagereach.org

Software Developer, Information Systems Group


VillageReach Starting at the Last Mile
2900 Eastlake Ave. E, Suite 230, Seattle, WA 98102, USA
CELL: +1.510.410.0020
SKYPE: nickdotreid
www.villagereach.org



From: openlm...@googlegroups.com <openlm...@googlegroups.com> on behalf of Brandon Bowersox-Johnson <brandon.bowe...@villagereach.org>
Sent: Friday, September 15, 2017 12:41:24 PM
To: Łukasz Lewczyński; OpenLMIS Dev
Subject: Re: [openlmis-dev] Concurrent requests
 

Nikodem Graczewski

unread,
Oct 3, 2017, 3:43:10 AM10/3/17
to OpenLMIS Dev
Hi,

I think the solution proposed by Nick could work, but I still have a little concern (and I think we should solve this issue on the back-end side) - what would happen if we just refresh the page and click the button again? If will send the second request in this case.

Best regards,
Nikodem

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

--
You received this message because you are subscribed to the Google Groups "OpenLMIS Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openlmis-dev...@googlegroups.com.
To post to this group, send email to openl...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages