每次使用来自应用引擎的数据存储都会超时

时间:2016-06-08 01:29:16

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

我第一次使用谷歌云环境专门使用谷歌应用引擎和数据存储区,当我在本地运行它时一切正常。我通过根据文档设置环境变量GOOGLE_APPLICATION_CREDENTIALS来对数据存储区进行身份验证。但是一旦我部署到app引擎,请求总是超时,似乎GetAll方法永远不会返回。以下是我的申请代码:

package app

import (
    "fmt"
    "net/http"
    "time"
    "golang.org/x/net/context"
    "google.golang.org/appengine"
    "google.golang.org/cloud/datastore"
)

type User struct {
    FirstName string
    LastName string
    Email string
    Created time.Time
    id      int64
}

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    var err error
    var dbClient *datastore.Client
    var ctx context.Context

    ctx = appengine.NewContext(r)

    dbClient, err = datastore.NewClient(ctx, "app-id")//this has the real app id, not sure if this is meant to be secret
    if err != nil {
        fmt.Fprintf(w, "Could not create datastore client: %+v", err)
        return
    }
    defer dbClient.Close()

    var users []*User

    query := datastore.NewQuery("User").Filter("Email=", "jcarm010@fiu.edu")
    keys, err := dbClient.GetAll(ctx, query, &users)
    if err != nil {
        fmt.Fprintf(w, "Could not query users: %+v", err)
        return
    }

    for i, key := range keys {
        users[i].id = key.ID()
        fmt.Fprintf(w, "%+v\n",users[i])
    }
    fmt.Fprintf(w, "done!!!")
}

App Engine日志中的错误有以下两行:

This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.

Process terminated because the request deadline was exceeded. (Error code 123)

顺便说一句,这在我的本地快速完成闪电,我的数据存储区中只有一条记录。有关为什么会发生这种情况或如何调试它的猜测? 感谢

2 个答案:

答案 0 :(得分:1)

datastore个软件包使用gRPC连接到数据存储区服务。您不能直接在App Engine上使用它,因为您无法直接建立TCP连接。

您需要使用sockets API为您建立TCP连接:

import "google.golang.org/appengine/socket" // et al

ctx := appengine.NewContext(r)
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

dialer := func(addr string, timeout time.Duration) (net.Conn, error) {
    return socket.DialTimeout(ctx, "tcp", addr, timeout)
}

client, err := datastore.NewClient(ctx, "app-id", cloud.WithGRPCDialOption(grpc.WithDialer(dialer)))

您还可以在调试时直接调用dialer,以确保它能够按预期到达datastore.googleapis.com:443:

conn, err := dialer("datastore.googleapis.com:443", 5*time.Second)
if err != nil {
    log.Errorf(ctx, "Dial: %v", err)
    http.Error(w, "Dial failed: "+err.Error(), http.StatusInternalServerError)
    return
}
fmt.Fprintf(w, "Addr: %v\n", conn.RemoteAddr())
conn.Close()

答案 1 :(得分:1)

我的问题的解决方案是切换数据存储库

来自:"google.golang.org/cloud/datastore"

至:"google.golang.org/appengine/datastore"

appengine / datastore似乎使用了不同的协议,因此您无需使用GOOGLE_APPLICATION_CREDENTIALS环境变量进行身份验证。当本地使用时,它将使用开发服务器用于不同的应用引擎服务,部署时将使用云资源。