dongyun7571 2018-10-11 04:06
浏览 42
已采纳

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

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...

  • 写回答

1条回答 默认 最新

  • douyunjiaok300404 2019-02-12 00:35
    关注

    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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?