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 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计