是否应根据Google App Engine的请求创建Firestore客户端?

时间:2018-10-11 04:06:23

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

我对如何解决这个问题感到困惑。

似乎GAE希望每个客户端库都使用一个context.Context范围为http.Request。

我以前有做过这样的事情的经验:

main.go

type server struct {
    db *firestore.Client
}

func main() {
    // Setup server
    s := &server{db: NewFirestoreClient()}

    // Setup Router
    http.HandleFunc("/people", s.peopleHandler())

    // Starts the server to receive requests
    appengine.Main()
}

func (s *server) peopleHandler() http.HandlerFunc {
    // pass context in this closure from main?
    return func(w http.ResponseWriter, r *http.Request) {
        ctx := r.Context() // appengine.NewContext(r) but should it inherit from background somehow?
        s.person(ctx, 1)
        // ...
    }
}

func (s *server) person(ctx context.Context, id int) {
    // what context should this be?
    _, err := s.db.Client.Collection("people").Doc(uid).Set(ctx, p)
    // handle client results
}

firebase.go

// Firestore returns a warapper for client
type Firestore struct {
    Client *firestore.Client
}

// NewFirestoreClient returns a firestore struct client to use for firestore db access
func NewFirestoreClient() *Firestore {
    ctx := context.Background()
    client, err := firestore.NewClient(ctx, os.Getenv("GOOGLE_PROJECT_ID"))
    if err != nil {
        log.Fatal(err)
    }

    return &Firestore{
        Client: client,
    }
}

这对如何确定项目范围内的客户有很大的影响。例如,挂起server{db: client}并在该结构上附加处理程序,或者必须通过请求内的依赖注入将其传递出去。

我确实注意到,使用客户端进行的呼叫需要另一个上下文。所以也许应该像这样:

  1. main.go创建一个ctx := context.Background()
  2. main.go将其传递给新客户端
  3. handler ctx := appengine.NewContext(r)

基本上,context.Background()的初始设置没有关系,因为新请求与App Engine具有不同的上下文?

我可以将ctx从main传递到处理程序中,然后再从该请求中传递NewContext吗?

什么是惯用的方法?

注意:在先前的迭代中,我也使用了Firestore结构的firestore方法...

1 个答案:

答案 0 :(得分:3)

您应该将firestore.Client实例重用于多次调用。但是,这在GAE标准的旧版Go运行时中是不可能的。因此,在这种情况下,您必须为每个请求创建一个新的firestore.Client

但是,如果您将新的Golang 1.11运行时用于GAE标准,则可以自由使用任何您喜欢的上下文。在这种情况下,您可以使用后台上下文在firestore.Client函数或main()函数中初始化init()。然后,您可以使用请求上下文在请求处理程序中进行API调用。

package main

var client *firestore.Client

func init() {
  var err error
  client, err = firestore.NewClient(context.Background())
  // handle errors as needed
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
  doc := client.Collection("cities").Doc("Mountain View")
  doc.Set(r.Context(), someData)
  // rest of the handler logic
}

这是我使用Go 1.11和Firestore实现的示例GAE应用,它演示了上述模式:https://github.com/hiranya911/firecloud/blob/master/crypto-fire-alert/cryptocron/web/main.go

GAE对Go 1.11的更多支持:https://cloud.google.com/appengine/docs/standard/go111/go-differences