【问题标题】:Go App Engine Writing to Google Datastore HangsGo App Engine 写入 Google Datastore 挂起
【发布时间】:2018-06-01 21:32:30
【问题描述】:

我正在使用 Go 编写一个简单的 App Engine 程序。我需要将一些数据写入 Google DataStore。当我尝试将数据放入存储时,程序一直挂起。这整个星​​期都困扰着我。

在某个时候,我设法将数据写入 DataStore,直到我发现如何在 Cloud Console 中查看上传的数据后才意识到这一点。从那以后我已经对代码进行了很多更改,现在我不能再写任何数据了。它每次都挂起。

日志显示没有任何帮助。仅通知该过程已超时。没有从程序写入的日志,仅从系统写入。

由于超出了请求期限,进程终止。 (错误代码 123)

我尝试使用this link 更改导入语句,但编译失败,所以我返回this link,编译没有问题。

我考虑到我的开发环境可能以某种方式严重错误配置(也许是毁容?),所以我去了一台干净的机器并仔细进行了新安装。它仍然挂起。

我的 app.yaml 文件:

runtime: go
    api_version: go1

handlers:
    - url: /.*
      script: _go_app

我添加的一个 index.yaml 文件:

indexes:

    - kind: Bacon
        properties:
    - name: YCode
        direction: asc
    - name: URL
    - name: Owner
    - name: Location

这是我的代码:

package main

    import (
        "fmt"
        "log"
        "net/http"
        "google.golang.org/appengine/datastore"
        "google.golang.org/appengine" 
    )

     type Bacon struct {
        YCode string
        URL string
        Owner string
        Location string
    } 

    func main() {
        http.HandleFunc("/", indexHandler)
        appengine.Main() 
    }

    func indexHandler(w http.ResponseWriter, r *http.Request) {

        ctx := appengine.NewContext(r)
        projectID := "fake-for-discussion-thread-787987"

        client, err := datastore.NewClient(ctx, projectID)
        if err != nil {
            log.Fatalf("Failed to create client: %v", err)
            return
        } 

        kind := "Bacon"
        name := "3"
        baconKey := datastore.NameKey(kind, name, nil)

        //Make bacon
        bacon := Bacon{
            YCode: "1",
            URL: "http://www.safeway.com",
            Owner: "Bob",
            Location: "Deli",
        }

        // I've confirmed that this is where it hangs every time.  
        // It doesn't even capture my silly fatal log entry. 
        // It just times out and finally sends a 500 Server Error.
        if _, err := client.Put(ctx, baconKey, &bacon); err != nil {
            log.Fatalf("Failed to save my Bacon: %v", err)
        }

        client.Close()

    }

非常感谢您提供的任何帮助!

【问题讨论】:

  • 嗯培根...这可能是因为上下文被使用了两次(NewClient 和 client.Put 中的 ctx)。尝试在 main 中创建一个长期存在的应用引擎客户端,并在请求处理程序中重用它。见example
  • 或者 datastore.NewClient 应该使用 context.Background() 而不是请求上下文创建。见example
  • 我开始认为在本地运行和在 App Engine 上运行之间的差异在很多在线文档中都没有得到很好的体现。恰当的例子:许多示例确实使用了 context.Background(),但是当我尝试它时,我收到了 App Engine 的拒绝,因为它“不是应用程序引擎上下文”。叹。所以我求助于将那段代码嵌入到 indexHandler 中,因为它生成了 r,我可以将它提供给 appengine.NewContext() 以获取 App Engine 发现的上下文。
  • 我确实设法通过挖掘此处引用的代码解决了这个问题:cloud.google.com/appengine/docs/standard/go/building-app/…。而且,更具体地说:github.com/GoogleCloudPlatform/golang-samples/blob/master/…。解决我的 Put 问题的方法是停止尝试创建客户端对象,只需调用 datastore.Put。繁荣!不再挂起,我的数据以极快的速度写入 Google 的 DataStore!
  • 所以这里的大收获:App Engine 在后台做了很多事情,并且很好地融入了他们的 DataStore 服务,只要你不尝试使用相同的代码约定在本地(或在非 App Engine 机器上)运行时可能工作。

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


【解决方案1】:

好的!所以这真的把我逼到了墙角,但今天早上我设法打破了它。我很难找到在线文档,我想确保我把我的(现在工作的)代码放进去,这样其他人就可以免于痛苦。

值得注意的是,如果您要部署到 App Engine,我开始怀疑 Go 文档/示例可能会让您走错路。 App Engine 不喜欢某些核心 Go 库等。在部署到 App Engine 时,这可能会变得非常混乱。

另外请注意,我从最初的问题中学到了很多经验教训。我正在输入此条目,以便我可以正确发布我的固定 App Engine 特定代码。

    //Modified to work on App Engine. May not work right locally, etc.

    package main

    import (
        "fmt"
        "log"
        "net/http"
        "google.golang.org/appengine/datastore"
        "google.golang.org/appengine" 
    )

     type Bacon struct {
        YCode string
        URL string
        Owner string
        Location string
    } 

    func main() {
        http.HandleFunc("/", indexHandler)
        appengine.Main() 
    }

    func indexHandler(w http.ResponseWriter, r *http.Request) {

        //This gives a context that makes App Engine happy      
        ctx := appengine.NewContext(r)

        //NOT NEEDED (Apparently, App Engine knows who you are. Creepy.)    
        //projectID := "fake-for-discussion-thread-787987" 

        //NOT NEEDED (And may actually cause you great woe!)
        //client, err := datastore.NewClient(ctx, projectID)
        //if err != nil {
        //  log.Fatalf("Failed to create client: %v", err)
        //  return
        //} 

        //Turns out that these aren't needed, either. 
        //kind := "Bacon"
        //name := "3"

        //Note the changes from my original code, including the
        //change from NameKey to NewIncompleteKey and the
        //hard-coding of Bacon in the arguments. Alternatively, you might
        //use a variable, depending on your needs. I just need bacon.
        //This causes the entity you create in Google DataStore 
        //to have a "Kind" of "Bacon"
        baconKey := datastore.NewIncompleteKey(ctx, "Bacon", nil)

        //Make bacon
        bacon := Bacon{
            YCode: "1",
            URL: "http://www.safeway.com",
            Owner: "Bob",
            Location: "Deli",
        }

        // Note changes here. No more client, just a call to datastore.Put.
        // Now it works!  One caveat: I'm still trying to figure out why it writes 
        // my data twice. But, hey!  At least it's writing!
        if _, err := datastore.Put(ctx, baconKey, &bacon); err != nil {
            log.Fatalf("Failed to save my Bacon: %v", err)
        }

        //No client, so no need to close.
        //client.Close()

    }

干杯!

【讨论】:

  • 重复数据问题似乎已经解决。非常简单:每次实例启动时,以及每次请求命中实例时,我都会执行编写代码:那就是两个!我将数据存储写入逻辑移动到仅在服务器请求时运行的条件中,现在它只写入一次。非常简单,令人耳目一新。
猜你喜欢
  • 2013-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2014-03-12
  • 2012-07-09
  • 2015-10-08
相关资源
最近更新 更多