简体   繁体   English

无论如何,在Google Cloud Datastore上每次插入/删除后都会收到回调吗?

[英]Is there anyway to get a callback after every insert/delete on Google Cloud Datastore?

I would like to sync my Cloud Datastore contents with an index in ElasticSearch. 我想将我的Cloud Datastore内容与ElasticSearch中的索引同步。 I would like for the ES index to always be up to date with the contents of Datastore. 我希望ES索引始终与Datastore的内容保持同步。

I noticed that an equivalent mechanism is available in the Appengine Python Standard Environment by implementing a _post_put_hook method in a Datastore Model . 我注意到,通过在数据存储Model实现_post_put_hook方法,可以在_post_put_hook Python标准环境中使用等效机制。 This doesn't seem to be possible however using the google-cloud-datastore library available for use in the flex environment. 但是,这似乎不可能使用可在flex环境中使用的google-cloud-datastore库。

Is there any way to receive a callback after every insert? 有没有办法在每次插入后收到回调? Or will I have to put up a "proxy" API in front of the datastore API which will update my ES index after every insert/delete? 或者我是否必须在数据存储区API之前放置一个“代理”API,它将在每次插入/删除后更新我的ES索引?

The _post_put_hook() of NDB.Model does only work if you have written the entity through NDB to Datastore, and yes, unfortunately the NDB library is only available in App Engine Python Standard Environment. _post_put_hook()NDB.Model如果您已经通过NDB写的实体数据存储不只是工作,是的,不幸的是,NDB库只适用于App Engine的Python标准环境。 I don't know of such feature in Cloud Datastore. 我不知道Cloud Datastore中有这样的功能。 If I remember correctly, Firebase Realtime Database or Firestore have triggers for writes, but I guess you are not eager to migrate the database neither. 如果我没记错的话,Firebase实时数据库或Firestore都有写入的触发器,但我想你并不急于迁移数据库。

In Datastore you would either need a "proxy" API with the above method as you suggested, or you would need to modify your Datastore client(s) to do this upon any successful write op. 在数据存储区中,您可能需要使用上述方法的“代理”API,或者您需要修改数据存储区客户端,以便在任何成功的写操作时执行此操作。 The latter may come with higher risk of fails and stale data in ElasticSearch, especially if the client is outside your control. 后者可能会出现更高的失败风险和ElasticSearch中的陈旧数据,特别是如果客户不在您的控制范围内。

I believe that a custom API makes sense if consistent and up-to-date search records is important for your use-cases. 我相信,如果一致和最新的搜索记录对您的用例很重要,那么自定义API就有意义了。 Datastore and Python / NDB (maybe with Cloud Endpoints) would be a good approach. 数据存储区和Python / NDB(可能使用云端点)将是一种很好的方法。

I have a similar solution running on GAE Python Standard (although with the builtin Search API instead of ElasticSearch). 我有一个类似的解决方案在GAE Python Standard上运行(尽管使用内置的Search API而不是ElasticSearch)。 If you choose this route you should be aware of two potential caveats: 如果您选择此路线,您应该了解两个潜在的警告:

  1. _post_put_hook() is always called, even if the put operation failed. 始终调用_post_put_hook() ,即使put操作失败也是如此。 I have added a code sample below. 我在下面添加了一个代码示例。 You can find more details in the docs: model hooks , hook methods , check_success() 您可以在docs中找到更多详细信息: model hookshook methodscheck_success()

  2. Exporting the data to ElasticSearch or Search API will prolong your response time. 将数据导出到ElasticSearch或Search API将延长您的响应时间。 This might be no issue for background tasks, just call the export feature inside _post_put_hook() . 这可能对后台任务没有问题,只需调用_post_put_hook()的导出功能_post_put_hook() But if a user made the request, this could be a problem. 但是如果用户提出请求,这可能是个问题。 For these cases, you can defer the export operation to a different thread, either by using the deferred.defer() method or by creating a push task). 对于这些情况,您可以通过使用deferred.defer()方法或通过创建推送任务将导出操作推迟到其他线程。 More or less, they are the same. 或多或少,它们是相同的。 Below, I use defer() . 下面,我使用defer()

  3. Add a class method for every kind of which you want to export search records. 为要导出搜索记录的每种类型添加类方法。 Whenever something went wrong or you move apps / datastores, add new search indexes etc. you can call this method that will then query all entities of that kind from datastore batch by batch, and export the search records. 每当出现问题或移动应用程序/数据存储区时,添加新的搜索索引等,您可以调用此方法,然后逐批从数据存储区查询该类型的所有实体,并导出搜索记录。

Example with deferred export: 延期导出示例:

class CustomModel(ndb.Model):
    def _post_put_hook(self, future):
        try:
            if future.check_success() is None:
                deferred.defer(export_to_search, self.key)
        except:
            pass  # or log error to Cloud Console with logging.error('blah')

def export_to_search(key=None):
    try:
        if key is not None:
            entity = key.get()
            if entity is not None:
                call_export_api(entity)
    except:
        pass  # or log error to Cloud Console with logging.error('blah')

``` ```

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM