I'm trying to achieve Strong consistency in datastore, don't know any other way to handle my requirement. Am having an application where users connect to each other randomly. so basically on 'connect' api call, it queries for QueueUser entities, if it doesn't find any, it will push calling user in the queue.
ofy().load().type(QueueUser.class)
.filterKey("!=", KeyFactory.createKey("QueueUser", caller.id))
.order("__key__")
.order("-time")
.limit(5)
.keys();
I understand that this will not fetch latest entity keys, as Indexes may not be up to date. so I interate through keys and get each entity by it's key. If I get a non-null entity, I'll try to delete it. If I succeed in that, I assume that it's a match of users. This get-by-key and delete() is inside Transaction.
while(keyIterator.hasNext()) {
QueueUser queueUser = null;
try {
final Key<QueueUser> key = keyIterator.next();
queueUser = ofy().transactNew(1, new Work<QueueUser>() {
public QueueUser run() {
QueueUser queueUser = ofy().load().key(key).now();
if(queueUser == null) {
logger.log(Level.WARNING, "queue user was already deleted");
return null;
}
else
ofy().delete().key(key).now();
return queueUser;
}
});
} catch (ConcurrentModificationException e) {
logger.log(Level.WARNING, "exception while deleting queue user. err: " + e.getMessage());
}
if (queueUser != null) {
// we have a match here
// delete calling user from the queue if it's there
ofy().delete().entity(new QueueUser(caller.id, null, null, null, null, null, null, null, null)).now();
break;
}
}
This works most of the time, but sometimes users get pushed in the queue and not picked up quickly. Request latency goes up to 15 seconds. Query returns lot of entities but most are deleted, and some gets deleted by peer request(expected ConcurrentModificationException).
I want to know if I am missing anything obvious here, or is there any better way to handle this.