Is there a suitable way to do optimistic locking w...
# prisma-whats-new
r
Is there a suitable way to do optimistic locking with GraphCool? (e.g. fail an update if a
version
field does not match). From what I can see the
update...
mutations only update by id.
a
It's possible to implement this, but it's going to take some effort. If your Type includes a version field, and you use that version in your mutations, you could use the `TRANSFORM_ARGUMENT`RP hook to query the current record by ID to check if the version matches, then increase it.
r
I considered this, but the resulting operation would not be atomic. If there are many concurrent queries modifying the same thing, two operations might check the version and think it's correct and then both change it without being aware of the other
a
They would actually, mutations are executed sequentially, and RP hooks are executed synchronously.
There's no such thing as a concurrent mutation with GraphQL. It's part of the spec.
r
Wow, I didn't know that, thank you for explaining that!
😎 1
d
Isn't that section of the spec referring to executing the mutations in a single request serially, rather than having a queue of mutations from all requests that are executed serially? As far as I know, the graphql spec does allow multiple requests to be executed in parallel.
Indeed, if graph.cool did not allow multiple concurrent requests, one slow request pipeline function could hold up processing for everyone else connecting to the same server.
r
I’ve had similar thoughts and am intending to run some simple tests to check this. I’ll be doing something like: Request Pipeline: Fetch data and check version field Request Pipeline: Sleep 5 seconds Request Pipeline: If same, increment field and return. Otherwise fail or maybe fetch data again Request Pipeline: Return new values I’ll run a few of these at once and if the field is not incremented the right amount then there’s a problem
d
I'm also doing some similar testing 😉 let's compare notes...
r
👍
a
It's actually written somewhere that all mutations are executed sequentially @ Graphcool. I'll try to find it...
d
I've been doing some experiments and I think I have demonstrated that mutations (in separate requests) are executed concurrently
I'm using this in a TRANSFORM_ARUMENT request pipeline function:
module.exports = function (event) { return new Promise(resolve => setTimeout(resolve,event.data.delay * 1000)); }
So it delays returning for a variable amount of time depending on what is in the data
If if send a mutation with delay 10, then a mutation with delay 2, the first one should completed first even with the delay, if mutations are queued and executed serially
however, the one with delay 2 completes first, as I would expect if mutations are executed in parallel
If I send the two mutations in the same request( i.e. separate mutation aliases in one outer mutation element) then they are processed serially
@agartha you may be thinking of the mention on this page that mutations are executed serially: https://www.graph.cool/docs/faq/graphql-combining-multiple-queries-and-mutations-cahzai2eur/
but i think that only applies to multiple mutations in a single request
r
For the purpose of optimistic locking, I’d want to know that once a request pipeline function had begun, another could not until the previous had completed. One being before the other isn’t an issue, just that they are effectively atomic in their side effects
d
My testing with the request pipeline function above indicates this is not the case - the second mutation can enter the request pipeline while the first one is 'sleeping'
a
Hmmm... Thank you for the testing, I knew this was the case for batched mutations, but I thought it applied to mutations in general.
There's no database level locking, so there's always going to be race conditions. The best you can do is minimize the risk I guess...
You could use a PQ, because they are 'closer' to the actual write, so increase version number in the RP hook, then check the version number in the update PQ.
d
What we really need is some kind of transaction support for this kind of use case
It may also be good to be able to mark specific mutation request pipelines as serial so that requests for them are queued and executed one at a time
r
I feel it could be quite simple to be able to specify a filter to an update mutation and then check in the response whether it succeeded. That’s classic optimistic locking. For that graphcool would just need to offer an optional filter to update mutations