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 docker环境配置
  • ¥20 绿盟安全扫描--检测到目标站点存在javascript框架库漏洞
  • ¥30 Android STD快速启动
  • ¥15 如何使用simulink建立一个永磁同步直线电机模型?
  • ¥30 天体光谱图的的绘制并得到星表
  • ¥15 PointNet++的onnx模型只能使用一次
  • ¥20 西南科技大学数字信号处理
  • ¥15 有两个非常“自以为是”烦人的问题急期待大家解决!
  • ¥30 STM32 INMP441无法读取数据
  • ¥15 R语言绘制密度图,一个密度曲线内fill不同颜色如何实现