根据GAE上的请求域提供不同的wsgiapplications,其中threadsafe:true

时间:2012-03-15 00:10:02

标签: google-app-engine python-2.7 wsgi

我想要做的是根据请求域加载不同的应用程序(webapp2.WSGIApplication)。 例如www.domain_1.com应该在app1.main.application中加载应用程序,而www.domain_2.com应该加载app2.main.appplication。
当然我在相同的GAE appid上,我使用命名空间来分隔应用数据。

这对'threadsafe:false'和一个runner.py文件非常有用,其中函数确定要返回的应用程序

似乎'threadafe:true'第一个请求将wsgiapplication加载到实例中,并且进一步请求不再执行'application dispatching'逻辑,以便请求从错误的应用程序获得响应。

即时通讯使用python2.7和webapp2

这样做的最佳方式是什么?

修改

我的runner.py的简化版本

def main():
    if domain == 'www.mydomain_1.com':
        from app_1 import application
        namespace = 'app_1'
    elif domain == 'www.domain_2.com':
        from app_2 import application
        namespace = 'app_2'
    namespace_manager.set_namespace(namespace)
    return wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()

和app.yaml

- url: /.*
  script: app-runner.py

2 个答案:

答案 0 :(得分:0)

您的跑步者脚本是CGI脚本。没有记录启用多线程的CGI脚本的完整行为,以及编写文档的方式我猜测这将不会得到完全支持。相反,文档说当你打开多线程时,你必须直接从app.yaml引用WSGI应用程序对象,使用包含该对象的全局变量的模块路径。 (CGI脚本在Python 2.7中保留了旧的行为,并关闭了多线程。)

您看到的行为可以通过使用导入来解释。在单个实例中,每个import语句仅在第一次遇到时生效。之后,假定导入模块,并且import语句对后续请求没有影响。您可以将这两个值导入单独的名称,然后使用适当的值调用run()

但是如果你想启用多线程(这是一个好主意),你的调度程序应该是一个WSGI应用程序本身,存储在app.yaml引用的模块全局中。我不知道如何从WSGI应用程序中向另一个WSGI应用程序发送请求,但这可能是一件合理的事情。或者,您可以考虑使用或构建WSGI上方的层来执行此调度。

答案 1 :(得分:0)

通过继承webapp2.WSGIApplication并覆盖在调度到RequestHandler之前调用的__call__()来实现。
为路由添加前缀(并删除处理程序初始化中的前缀)和子结构配置以便能够使用实例内存。

class CustomWSGIApplication(webapp2.WSGIApplication):

    def __call__(self, environ, start_response):

        routes, settings, ns = get_app(environ)
        namespace_manager.set_namespace(ns)

        environ['PATH_INFO'] = '/%s%s' %(ns, environ.get('PATH_INFO'))

        for route in routes:
            r, h     = route # returns a tuple with mapping and handler
            newroute = ('/%s%s'%(ns, r), h,)
            self.router.add(newroute)


        if settings:
            self.config[ns] = settings

        self.debug  = debug

        with self.request_context_class(self, environ) as (request, response):
            try:
                if request.method not in self.allowed_methods:
                    # 501 Not Implemented.
                    raise exc.HTTPNotImplemented()

                rv = self.router.dispatch(request, response)
                if rv is not None:
                    response = rv
            except Exception, e:
                try:
                    # Try to handle it with a custom error handler.
                    rv = self.handle_exception(request, response, e)
                    if rv is not None:
                        response = rv
                except HTTPException, e:
                    # Use the HTTP exception as response.
                    response = e
                except Exception, e:
                    # Error wasn't handled so we have nothing else to do.
                    response = self._internal_error(e)

            try:
                return response(environ, start_response)
            except Exception, e:
                return self._internal_error(e)(environ, start_response)