获取给定类型的所有实体(本地云端点)时对象化不一致

Objectify inconsistency when getting all entities of a given kind (local Cloud Endpoints)

我在尝试使用 Objectify 加载给定种类的所有实体时遇到不一致。

设置

我是 运行 本地的 Cloud Endpoints 后端,并使用以下方法填充 Datastore:

  public static void dsUp() {
    Store store1 = new Store("H&M", new GeoPt(new Float(56.157702), new Float(10.206938)));
    Store store2 = new Store("Marc Jacobs", new GeoPt(new Float(56.158284), new Float(10.208618)));
    Store store3 = new Store("Weekday", new GeoPt(new Float(56.158522), new Float(10.207547)));

    ofy().save().entities(store1, store2, store3).now(); // Synchronous save to auto generate id
}

设置数据库后,数据存储区查看器显示创建了所有三个对象:

问题

我开始注意到我的客户端应用程序 (iOS) 有时只收到两个商店:

我重新访问了后端的 getStores() 方法,并将其更改为加载所有商店 4 次,记录每次尝试,最后 return 获取第一次尝试的结果。

该方法(将其更改为多次加载尝试后)如下所示:

 public static List<Store> getStores() {

    List<Store> result = ofy().load().type(Store.class).list();
    LOGGER.warning("Getting Stores, try 1: " + result.toString());
    LOGGER.warning("Getting stores, try 2: " + ofy().load().type(Store.class).list());
    LOGGER.warning("Getting stores, try 3: " + ofy().load().type(Store.class).list());
    LOGGER.warning("Getting stores, try 4: " + ofy().load().type(Store.class).list());

    return result; // Returning the results from try 1
}

通常,所有三个商店每次尝试 returns。但是,有时候第一次试,甚至第二次试都会return只有两家店。到第三次和第四次尝试时,所有商店都已 returned。

其中一个方法调用的记录输出如下所示。请注意,这次都尝试 1 和 2 return 只编辑了两个商店。

我看不到任何在数据库重置之间遗漏商店的模式。有时是一个,有时是另一个。但是,似乎在对 getStores() 的同一次调用中,如果尝试 1 和 2 都失败,则它似乎缺少相同的商店(如上图所示)。

我尝试了什么?

我最初的想法是,我一定是将 Objectify 过滤器设置错了。但是,据我所知,这似乎是有序的。在我的 webapp/WEB-INF/web.xml 文件中,我有以下过滤器和过滤器映射:

<filter>
    <filter-name>ObjectifyFilter</filter-name>
    <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ObjectifyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

我对 Objectify 的缓存还不是很熟悉,但我尝试了以下方法:

在加载任何实体之前,在后端的 getStores() 方法中添加以下行作为第一件事:

  ofy().clear(); // Clear the cache

我也试过在加载实体时使用STRONG一致性,如下:

    List<Store> result = ofy().consistency(ReadPolicy.Consistency.STRONG).load().type(Store.class).list();

其他可能相关的信息

我可以重现不一致,它发生了大约 1/5 次。但是,据我所知,只有在使用前面提到的 dsUp() 方法从头开始设置数据库后才会发生这种情况。

两次尝试之间我使用以下方法清除数据库:

public static void dsDown() {
    List<Key<Store>> allStoreKeys = ofy().load().type(Store.class).keys().list();
    ofy().delete().keys(allStoreKeys).now();
}

就数据存储查看器而言,dsDown() 方法按预期工作并使数据库为空。据我了解,直接在数据库查看器中删除实体可能会导致缓存未被删除的问题。但是我已经读到,像在 dsDown() 方法中那样使用 Objectify 删除实体可以避免这个问题。

如果我需要提供任何其他信息,请告诉我。

谢谢!

编辑(我从@saiyr 实施解决方案):

正如@saiyr 指出的那样,数据存储在本地 运行 时模拟最终一致性,这导致了不一致。以下屏幕截图显示了我如何将标志添加到后端模块的 build.gradle 文件中。

注意: 请注意,如果您完全关闭模拟最终一致性(将标志设置为 0),可能会导致 Objectify 事务出错。这就是我将标志设置为 1 的原因。有关这方面的更多信息,请参阅 this stack overflow post

您想将标志添加到后端项目的 build.gradle 文件中:

开发服务器数据存储emulates eventual consistency. Your setting the consistency to STRONG in Objectify is a no-op, because you can't enforce strong consistency on non-ancestor queries。对于开发服务器,您可以尝试将 datastore.default_high_rep_job_policy_unapplied_job_pct 值设置为零来解决此问题,但请注意,这只会影响本地开发。