0
votes

I receive presence packets from Google XMPP server in the /_ah/xmpp/presence/available/ path of my app engine application.

The thing is that I receive many packets in a few milliseconds (I have several bots behind myapp.appspotchat.com) and I must query the datastore and check wether the user whom presence packet is received has been already registered.

For some reason, I get two available presence packets for each user, and I noticed that an entry for the client was written twice into the datastore. My guess was that when the second packed arrived, the write triggered by the first packed was somehow not commited/consolidated.

So I decided to wrap the read and the write operations inside a transaction. Now the second packet does not cause a duplicate entry on the datastore. But, receiving so many consecutive packets eventually causes an exception to be thrown (java.util.ConcurrentModificationException: too much contention on these datastore entities).

Now, I have four questions:

  • Why do I receive two presence packets from each user?
  • Is correct my guess that the data was not in the datastore yet because the requests where too close?
  • Should I care of the presence packets not processed due to the mentioned exceptions?
  • How could I make the requests wait for the transaction to finish and be able to process them?

UPDATE:

I was wrong, the transaction is not stopping the second request to not find the entry in the datastore. This is the code snippet (I have not any index in the app engine):

XMPPService xmppService = XMPPServiceFactory.getXMPPService();
Presence presence = xmppService.parsePresence(req);
JID from_jid = presence.getFromJid();
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Key sessionKey = KeyFactory.createKey("Session", "default");

Transaction txn = datastore.beginTransaction();
Query query = new Query("Client", sessionKey).addFilter("jid", FilterOperator.EQUAL, from_jid.getId());
List<Entity> clients  = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(1));

if (clients.isEmpty()) {
    Entity client = new Entity("Client", sessionKey);
    client.setProperty("jid", from_jid.getId());
    datastore.put(client);
}
txn.commit();

Why the query returns an empty list?

1

1 Answers

0
votes

Configuring <threadsafe>false</threadsafe> in appengine-web.xml forces App Engine to send the requests sequentially and orderly and fixes the problems mentioned in the question.