我正在尝试在Go编写的AppEngine(标准环境)应用程序中使用Firestore。我一直在关注“Getting Started with Cloud Firestore"指南并且一直在使用firestore package文档来实现一个在我的本地开发服务器上运行它时工作正常的简单示例。
但是,当我部署应用程序并尝试部署的版本时,对DocumentRef.Set()
的调用失败并显示错误
rpc error: code = Unavailable desc = all SubConns are in TransientFailure
这是我的代码重现了这个问题:
func init() {
http.HandleFunc("/test", testHandler)
}
type testData struct {
TestData string `firestore:"myKey,omitempty"`
}
func testHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
var firestoreClient *firestore.Client
var firebaseApp *firebase.App
var err error
conf := &firebase.Config{ProjectID: "my-project"}
firebaseApp, err = firebase.NewApp(ctx, conf)
if err != nil {
fmt.Fprintf(w, "Failed to create a new firestore app: %v", err)
return
}
firestoreClient, err = firebaseApp.Firestore(ctx)
if err != nil {
fmt.Fprintf(w, "Failed to create a new firestore client: %v", err)
return
}
data := testData{"my value"}
_, err = firestoreClient.Collection("testCollection").Doc("testDoc").Set(ctx, data)
if err != nil {
fmt.Fprintf(w, "Failed to create a firestore document: %v", err)
return
}
firestoreClient.Close()
fmt.Fprint(w, "Data stored in Firestore successfully")
}
如前所述,在开发服务器上,这很好用。所以返回的页面包含文本Data stored in Firestore successfully
。
运行部署的代码时,我得到Failed to create a firestore document: rpc error: code = Unavailable desc = all SubConns are in TransientFailure
。为什么我会收到此错误,如何避免此错误?
我在Firestore客户端库问题跟踪器中提出了一个issue,看起来情况有点复杂。
使用App Engine时,Firestore客户端库的网络连接通过App Engine socket library进行。但是套接字仅适用于paid App Engine apps:
套接字仅适用于付费应用,来自套接字的流量将作为传出带宽计费。套接字也受每日和每分钟(突发)配额的限制。
所以这就是Firestore客户端库失败的原因。对于小规模项目,可以启用App Engine应用程序的计费并仍然保持在免费范围内。如果启用了计费,则在部署应用程序时也应该有效。
但是,如果您居住在欧盟范围内,由于Google policies,您不得出于非商业目的使用付费App Engine应用程序:
如果您位于欧盟,并且您希望使用Google Cloud Platform服务的唯一目的没有潜在的经济利益,则您不应使用该服务。如果您已开始使用Google Cloud Platform,则应停止使用该服务。请参阅创建,修改或关闭结算帐户,了解如何禁用项目结算。
因此,如果您在欧洲或由于某些其他原因无法使用付费App Engine应用程序,您将无法使用Firestore客户端库。
在这种情况下,一种替代方法是使用Firestore REST API代替手动向Firestore发出HTTP请求。这是一项更多的工作,但对于规模较小的项目,它的工作原理。
在AppEngine上,您需要创建一个使用urlfetch服务提供的Http客户端的客户端。
firestore.NewClient()
函数接受可以使用ClientOptions
函数创建的WithHTTPCLient()
参数。
这是一篇关于issuing HTTP requests from AppEngine Go的文章。
这应该有所帮助。