我如何管理App Engine Go运行时上下文以避免App Engine锁定?

Ant*_*iMS 19 google-app-engine go

我正在编写一个Go应用程序来运行App Engine的Go运行时.

我注意到几乎任何使用App Engine服务的操作(例如数据存储区,邮件甚至功能)都要求您传递一个appengine.Context必须使用该函数检索其实例的操作appengine.NewContext(req *http.Request) Context.

当我为App Engine编写这个应用程序时,我希望能够轻松快速地将其移动到其他平台(可能是一个不支持任何App Engine API的应用程序).

因此,我通过围绕任何特定于App Engine的交互(包括请求处理函数)编写小包装来抽象出与App Engine服务和API的实际交互.通过这种方法,如果我希望转移到不同的平台,我将只重写那些将我的应用程序绑定到App Engine的特定模块.简单直接.

唯一的问题是那个appengine.Context对象.我不能将我的请求处理程序通过我的逻辑层传递给处理这些API的模块,而不会将我的所有代码都绑定到App Engine.我可以通过http.Request从该对象appengine.Context物体可以得出,但这需要,可能不应该再加耦合的事情.(我认为最好的做法是我的应用程序都不知道它是一个Web应用程序,除了那些专门用于处理HTTP请求的部分.)

想到的第一个解决方案是在某个模块中创建一个持久变量.像这样的东西:

package context

import (
    "appengine"
)

var Context appengine.Context
Run Code Online (Sandbox Code Playgroud)

然后,在我的请求处理程序中,我可以使用context.Context = appengine.NewContext(r)和在直接使用App Engine服务的模块中设置该变量,我可以通过访问来获取上下文context.Context.没有干预代码需要知道appengine.Context对象的存在.唯一的问题是"多个请求可能由给定实例同时处理",这可能导致竞争条件和此计划的意外行为.(一个请求设置它,另一个设置它,第一个访问它并获取错误的appengine.Context对象.)

我理论上可以存储appengine.Context到数据存储区,但是我必须将一些特定于请求的标识符传递给逻辑层到特定于服务的模块,以识别appengine.Context数据存储区中哪个对象是当前请求的对象,这将再次耦合事物我认为不应该耦合.(而且,它会增加我的应用程序的数据存储使用率.)

我也可以appengine.Context使用整个类型的类型将对象传递给整个逻辑链,interface{}并且任何不需要该appengine.Context对象的模块都会忽略它.这将防止占压我的大多数应用程序的任何东西具体.然而,这似乎也非常混乱.

所以,我有点不知道如何干净地确保需要该appengine.Context对象的App-Engine特定模块可以获得它.希望你们大家能给我一个解决方案,我还没有想到自己.

提前致谢!

Ric*_*777 8

这很棘手,因为你自己施加的范围规则(这是一个明智的规则)意味着不传递一个Context实例,并且没有任何类似于Java的方法ThreadLocal可以通过偷偷摸摸的方式实现相同的目的.这真的是一件好事.

Context结合日志记录支持(简单)和一个Callappengine服务(不容易).我认为有十个需要一个的appengine函数Context.我看不到任何干净的解决方案,除了将所有这些包裹在你自己的外观后面.

有一件事可以帮助您 - 您可以在应用程序中包含一个配置文件,指示它是使用GAE还是其他方式,使用某种标志.您的全局布尔值只需存储此标志(不是共享上下文).然后,在决定是否使用NewContext(r)获取Context访问GAE服务或使用类似结构访问您自己的替代服务时,您的外观功能可以查阅此标志.

编辑:作为最后的评论,当你解决这个问题时,我可以邀请你分享你是如何做到的,甚至可能是开源项目?厚颜无耻地问我,但如果你不问...... ;-)


小智 7

我(希望)通过包装我的请求处理程序(在此示例中称为"realHandler")来解决此问题,如下所示:

http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ds := NewDataStore(r)
    realHandler(w, r, ds)
})
Run Code Online (Sandbox Code Playgroud)

NewDataStore创建一个DataStore,它是一个抽象GAE数据存储区的简单包装器.它有一个未暴露的字段,用于存储上下文:

type DataStore struct {
    c appengine.Context
}

func NewDataStore(req *http.Request) *DataStore {
    return &DataStore{appengine.NewContext(req)}
}
Run Code Online (Sandbox Code Playgroud)

在请求处理程序中,我可以在需要时访问抽象的数据存储区,而不必担心已经设置的GAE上下文:

func realHandler(w http.ResponseWriter, req *http.Request, db *DataStore) {
    var s SomeStruct{}
    key, err := db.Add("Structs", &s)
    ...
}
Run Code Online (Sandbox Code Playgroud)