12

I'm using Flask to build my web application, and I'd like to register a global resource that represents a connection to a remote service which lasts longer than a request (in this case, the connection is a SOAP connection which can be valid for up to 30 days).

Another example could be a database like MongoDB which handles connection-pooling in the driver, and would perform badly if you created a new connection on each request.

Neither the Application Context, nor the Request Context seem appropriate for this task.

The question "Pass another object to the main flask application" suggests that we store such resources on the app.config dictionary.

Community
  • 1
  • 1
idbentley
  • 4,188
  • 3
  • 34
  • 50
  • 1
    Why does the application context not seem appropriate? –  Oct 23 '13 at 16:15
  • I find the documentation in this area confusing. I would like to setup these connections at application creation time, but I can't find a way in the API to do so. Can you provide an example? – idbentley Oct 23 '13 at 16:22
  • 1
    Use application context. The exact use case you cite is demonstrated in the [docs](http://flask.pocoo.org/docs/appcontext/) – doog abides Oct 23 '13 at 17:32
  • 1
    I may be misunderstanding, but this isn't the same as what I'm trying to do. In this case, you are using the Application context to manage creating and destroying connections with each request. I want to use a resource that does not need such management, my app only needs access to it. – idbentley Oct 23 '13 at 17:36
  • Have you considered subclassing application class `Flask` and add your own stuff there? Be careful though, your shared resources should be thread safe if your server is multi-threaded. – Miguel Grinberg Oct 23 '13 at 17:51
  • "__I would like to setup these connections at application creation time__" You can load the application context from environment variables, or static files as mentioned in the documentation, if that's part of your app's initialization code, it's going to be set at app creation. – Doobeh Oct 23 '13 at 18:34
  • 1
    @Doobeh I'm not worried about getting the configurations - that is straightforward enough. I'm trying to understand where and how to store the configured resource for global (within an app context) access. I *think* after reading these comments that the application context is the right place, but I'm still not understanding quite right. – idbentley Oct 23 '13 at 20:18
  • Just put the resources in the model level as what MongoDB driver does. The resources will alive until the end of Flask, don't them? – IvanaGyro Sep 24 '19 at 15:41

2 Answers2

5

If it MUST coincide with the instantiation of your app, then you should subclass Flask. This really doesn't do a whole lot if all your doing is attaching a resource to the object, considering the creation of the app is a process. Truth is, you probably don't need to do this if the application doesn't need to use your resource during instantiation.

class MyApp(Flask):
    def __init__(self, *args, **kwargs):
        setattr(self, 'some_resource', SomeResource())
        super(Flask, self).__init__(*args, **kwargs)

app = MyApp(__name__)
app.some_resource.do_something()

Unless you have some specific use case, you are probably better off writing a wrapper class, turning it into a flask-extension, creating it on the module level and storing it on app.extensions.

class MyExtensions(object):
    def __init__(self, app=None):
        self.app = app
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.extensions['my_extension'] = SomeResource()

app = Flask(__name__)
my_extension = MyExtension(app)

Then you can choose if you want to give each app its own resource (like above), or if you'd rather use a shared resource that is always pointing to the current app

from flask import _request_ctx_stack
try:
    from flask import _app_ctx_stack
except ImportError:
    _app_ctx_stack = None

stack = _app_ctx_stack or _request_ctx_stack

class SomeResource(object):
    def do_something(self):
        ctx = stack.top
        app = ctx.app
my_resource = SomeResource()
my_resource.do_something()

I don't think you want to store this on the application context, because " it starts when the Flask object is instantiated, and it implicitly ends when the first request comes in"

Instead, you want your resource created at the module level. Then you can attach it to the application as an extension, or yes, even in the config- though it would be more consistent and logical to make a quick extension out of it.

tryexceptcontinue
  • 1,587
  • 15
  • 13
  • IMO `current_app.extensions['my_extension']` is the best approach. – zengr Aug 24 '14 at 20:25
  • 1
    It's a common practice to share a database connection across requests. But I think the documentation at Flask website is very misleading. Actually database connections will be established for every request as described here. http://flask.pocoo.org/docs/0.10/appcontext/ – Hanson Nov 08 '15 at 14:25
0

This is a Python problem, the reason Flask and other web frameworks do not allow this/make it very difficult is because there is no defined memory model for concurrency. E.g. suppose your webserver serves requests in their own processes (e.g. Gunicorn). This will result in processes forking off the main process, and thus copying your "global" variable. If you run a server on windows then due to the lack of a fork it will instead make a new process which reimports all modules, probably producing a clean version of your global state which does not remember any changes made to it in the main process pre-thread. Or not finding it at all if you declare it behind a name guard.

There are only two possible ways to consistently do this "right". One is to build a webapp specifically to hold your global state and which is restricted to a single thread, and have your other webapp call state from this webapp.

The second, is to use Jython + threads. Since Jython runs in a JVM it has a well defined memory model with shared state, so you can use all the java EE tricks like container managed concurrency....

SiHa
  • 7,830
  • 13
  • 34
  • 43
phil_20686
  • 4,000
  • 21
  • 38