I am using GAE SDK 1.8.9 with Java 1.7 (build 45). For the datastore, I am using Datanucleus JDO v2. I have deployed code to production to update a counter for each new "order" request and am having a couple of consistency issues occurring that I believe are related to the processing of the requests from different servers within a few seconds of each other. The datastore entity consists of a unique key (generated by my app), a couple of date fields, and an orderId counter. There are only a few of these entities in the datastore.
Here is a subset of my logic...
keyId is an instance variable of type String within a StoreWrapper class
The newOrderId() method within the StoreWrapper class should fetch the desired Store entity (based on the keyId) within the datastore, increment the entity's orderId value, update the entity back to the datastore with the updated value, and finally return the updated value (or 0 if an error occurs) to the caller. The fetching, incrementing, and updating all occur within a JDO transaction using the .begin() and .commit() method for a transaction.
The newOrderId() method within the Store class simply increments the orderId value (plus some logic to allow it to rollover once it reaches a ceiling).
public int newOrderId() { int orderId = 0;
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
Store tempStore = null;
try {
tx.begin(); // Use a transaction to modify value (read, update, write)
tempStore = pm.getObjectById(Store.class, keyId);
tempStore.newOrderId();
pm.makePersistent(tempStore); // Problem occurs regardless if this statement exists or not
tx.commit();
orderId = tempStore.getOrderId();
} catch (JDOObjectNotFoundException e) {
// Do new store stuff
...
} catch (JDOUserException e) {
System.out.println(e.getMessage());
} catch (JDODataStoreException e) {
System.out.println(e.getMessage());
} catch (JDOCanRetryException e) {
System.out.println(e.getMessage());
} catch (JDOOptimisticVerificationException e) {
System.out.println(e.getMessage());
} catch (JDOFatalException e) {
System.out.println(e.getMessage());
} catch (JDOException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (tx.isActive())
tx.rollback();
pm.close();
}
return orderId;
}
When I submit several requests to place an order over a short period, I notice duplicate order numbers in another datastore for the orders. My research has concluded this occurs when multiple instances are processing the requests. In the logs, I can see that each time this occurs, the instance is different for the duplicates. It is my understanding that the entity group defaults to the root (which would be the case for this situation given the simple nature of the entity since I don't specify a parent when generating the key), but nowhere can I find a clear understanding as to why the behavior is acting like "eventual consistency" rather than "strong consistency". I've placed several catches for the various exceptions, but see no evidence that any of these are occurring in the logs. I've even set the threadsafe to 'false' so only one request is processed per instance and it still occurs. Is there some setting that must be set to enforce "strong consistency" across the multiple instances?