并发数据存储区操作;这么多XMPP存在包

时间:2014-09-26 16:00:29

标签: google-app-engine xmpp google-cloud-datastore

我在应用引擎应用的/_ah/xmpp/presence/available/路径中收到来自Google XMPP服务器的状态信息包。

问题是我在几毫秒内收到了很多数据包(我在myapp.appspotchat.com后面有几个机器人)并且我必须查询数据存储区并检查用户是否已经注册了接收存在数据包。

出于某种原因,我为每个用户获得两个 可用的状态数据包,我注意到客户端的一个条目被写入数据存储区两次。我的猜测是,当第二个打包到达时,由第一个打包引发的写入在某种程度上不会被提交/合并。

所以我决定将读取和写入操作包装在事务中。现在,第二个数据包不会在数据存储上导致重复条目。但是,接收如此多的连续数据包最终会导致抛出异常(java.util.ConcurrentModificationException: too much contention on these datastore entities)。

现在,我有四个问题:

  • 为什么我会收到每个用户的两个在线状态数据包?
  • 我猜这个数据还没有在数据存储中,因为请求太近了吗?
  • 我是否应该关注由于上述例外情况而未处理的状态数据包?
  • 如何让请求等待事务完成并能够处理它们?

更新:

我错了,事务没有停止第二个请求在数据存储区中找不到该条目。这是代码片段(我在应用引擎中没有任何索引):

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();

为什么查询返回一个空列表?

1 个答案:

答案 0 :(得分:0)

<threadsafe>false</threadsafe>中配置appengine-web.xml会强制App Engine按顺序有序地发送请求,并修复问题中提到的问题。