I have reached an issue in Grails which I think could be a potential issue with how concurrency is handled; and I am unsure of how to best handle this (or if there is a solution / practice already in place I can adapt).
Background
My Grails application is serving as a REST API, and has an enciphering method for data which relies on a counter variable as a salting mechanism for the cipher.
This counter variable must be maintained, and cannot be lower as the data is going to a SIM card where the counter can not be modified post-issuance, therefore it is important that I maintain this counter correctly. Additionally, if the counter is incorrect, the message will be rejected by the SIM.
When a user calls, for example: http://example.tld/service/controller/action?id=1
the server will do the following:
get
the objectcontroller
with identifier1
- Modify the
counter
member/row of the object save
the object
This has been fine, for over 20,000 requests. However, twice, I have had a StaleObjectException
which I have determined to happen due to the object being accessed at the exact same time. I have determined that this is happening as the wrapper API I have provided uses ten threads, and by chance both threads have called the action
at the same time.
I have read and noted that I can either:
- Turn off Optimistic Locking (this seems like a bad idea)
- Turn on dynamic updates (I don't think that this will help me, as I am still updating the same row at the same time)
lock
the object -- but I think this will still raise an Exception due to the object being locked the second time it is accessed?- Use
executeUpdate
which I think is similar to turning on Dynamic Updates? Perhaps not useful in my use case.
Question
I am wondering if there's perhaps some transaction mechanism I can use? I.e. a method to check if an object is currently locked, and if so, sleep for t
to allow the transaction to complete in the database.
Ultimately, my end goal is to not reject any requests, therefore if the transaction mechanism above exists (which I assume will be some sort of pessimistic lock) and said transaction mechanism rejects the request as the object is locked, I would rather some other solution as I want to avoid at all costs rejecting requests to the service as it complicates prior deliveries to clients.
The current solution I am thinking of is to just:
try {
Foo.save()
catch (RespectiveException ex) {
Thread.sleep(1000)
if(depth < 3) {
recursiveCallToThisMethod(depth++)
} else {
render(letTheUserKnowWhyItFailed)
}
}
But yeah... Pretty ugly.