Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I think the problem is not about updating the product count atomically -- the <code>F()</code> expression for Django ORM should handle that correctly. However the combined operation of:</p> <ol> <li>Checking order status (does product count need update?)</li> <li>Updating product count</li> <li>Updating order status (to cancelled)</li> </ol> <p><strong>is not an atomic operation</strong>. It is possible to have the following sequence of events for two threads A and B (both handling cancel request for the same order):</p> <blockquote> <p>A: Check order status: new is cancel, differs from previous one <br> B: Check order status: new is cancel, differs from previous one <br> A: Update product count atomically from 0 to 1 <br> B: Update product count atomically from 1 to 2 <br> A: Update order status to cancelled <br> B: Update order status to cancelled <br></p> </blockquote> <p>What you need to do is one of the following:</p> <ol> <li>Change the whole operation to occur within a transaction. You didn't mention your database or transaction mode setup. Django defaults to autocommit mode where each database operation is commited separately. To change to transactions (probably tied to the HTTP request), see <a href="https://docs.djangoproject.com/en/dev/topics/db/transactions/" rel="nofollow">https://docs.djangoproject.com/en/dev/topics/db/transactions/</a></li> <li>Create a synchronization barrier to prevent both threads from updating the product count. You could do this with an atomic compare-and-swap operation on the database layer, but I'm not sure whether there's a ready <code>F</code> or similar primitive to do this. (The main idea is to change the ordering of order and product data updates so that you first update and test atomically the order status.)</li> <li>Use some other form of synchronization mechanism, using a distributed lock system (you can use Redis and many other systems for this). I think this would be overkill for this case, though.</li> </ol> <p><strong>In summary:</strong> Unless you are using HTTP-level transactions for your application already, try setting <code>ATOMIC_REQUESTS = True</code> in your Django configuration file (<code>settings.py</code>).</p> <p>If you don't or can't do that please note that the alternative methods do not give you order-product pair consistency. Try to think what will happen if the Django server crashes between updates to the product and the order -- only one will be updated. (This is where database transactions are a must where the database engine notices that the client aborted -- due to broken network connection -- and rolls back the transaction.)</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload