是否应根据Google App Engine的请求创建一个Firestore客户端? [英] Should a Firestore client be created per a request with Google App Engine?

查看:37
本文介绍了是否应根据Google App Engine的请求创建一个Firestore客户端?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

main.go

 类型服务器结构{db * firestore.Client}func main(){//安装服务器s:=& server {db:NewFirestoreClient()}//设置路由器http.HandleFunc("/people",s.peopleHandler())//启动服务器以接收请求appengine.Main()}func(s * server)peopleHandler()http.HandlerFunc {//通过main在此闭包中传递上下文?return func(w http.ResponseWriter,r * http.Request){ctx:= r.Context()//appengine.NewContext(r),但是它应该以某种方式从后台继承吗?s.person(ctx,1)//...}}func(s * server)person(ctx context.Context,id int){//这应该是什么上下文?_,err:= s.db.Client.Collection("people").Doc(uid).Set(ctx,p)//处理客户结果} 

firebase.go

 //Firestore返回客户端的包装器输入Firestore struct {客户端* firestore.Client}//NewFirestoreClient返回一个用于存储数据库访问的存储结构客户端func NewFirestoreClient()* Firestore {ctx:= context.Background()客户端,错误:= firestore.NewClient(ctx,os.Getenv("GOOGLE_PROJECT_ID"))如果err!= nil {log.Fatal(错误)}返回& Firestore {客户:客户,}} 

这对如何确定项目范围内的客户有很大的影响.例如,挂起 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方法...

解决方案

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

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

 程序包主要var client * firestore.Clientfunc init(){var err错误客户端,err = firestore.NewClient(context.Background())//根据需要处理错误}func handleRequest(w http.ResponseWriter,r * http.Request){doc:= client.Collection(城市").Doc(山景")doc.Set(r.Context(),someData)//其余的处理程序逻辑} 

这是我使用Go 1.11和Firestore实现的GAE应用示例,它演示了上述模式: https://cloud.google.com/appengine/docs/standard/go111/go-differences

I'm confused on how to approach this.

It seems to be that GAE wants every client library to use a context.Context scoped to a http.Request.

I previously have experience doing something like this:

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,
    }
}

This has big implications on how to scope a project wide client. E.g hanging off of a server{db: client} and attaching handlers on that struct or having to pass it off via dependency injection within the request.

I do notice that the calls out using the client require another context. So maybe it should be like:

  1. main.go create a ctx := context.Background()
  2. main.go pass that into new client
  3. handler ctx := appengine.NewContext(r)

Basically the initial setup doesn't matter off of context.Background() because new requests have a different context from App Engine?

I could pass in ctx into the handler from main and then NewContext off of that + the request?

What's the idiomatic approach to this?

note: I had firestore methods off of the Firestore struct as well in previous iterations...

解决方案

You should reuse the firestore.Client instance for multiple invocations. However, this was not possible in the old Go runtime in GAE standard. So in that case you must create a new firestore.Client per request.

But if you use the new Golang 1.11 runtime for GAE standard, then you're free to use any context you like. In that case you can initialize firestore.Client in the main() function or in an init() function using the background context. Then you can make API calls in the request handlers using the request context.

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
}

Here's an example GAE app that I've implemented using Go 1.11 and Firestore that demonstrates the above pattern: https://github.com/hiranya911/firecloud/blob/master/crypto-fire-alert/cryptocron/web/main.go

More on the Go 1.11 support in GAE: https://cloud.google.com/appengine/docs/standard/go111/go-differences

这篇关于是否应根据Google App Engine的请求创建一个Firestore客户端?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆