-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sharing db connection to nested nested app #2689
Comments
We can organize a kind of chained maps, like https://docs.python.org/3/library/collections.html#collections.ChainMap It breaks subapp isolation by definition but maybe we can live with it. |
May I suggest a concept called ‘runtime’. The instance is building a computation graph when handlers and start up progress are registered, which is used to describe when it should be run(triggered by signal). When the app is running, the triggered coroutine is called ‘runtime’. So the db is set during the runtime of startup. While now aiohttp will first triggered the startup runtime of the subapps, which leads to the absence of the db, we can add a node (of the graph) before the node of the startup of the sub-app, so we can ensure the existence of db at runtime. Thus in this manner, the outside app will first register a node to init db and the db config of the intermediate app is then triggered(which is set by the top app) and then the intermediate app triggers the db config of the inner apps(which means a new way to organize startup process should be introduced and the graph is built just as how those apps are nested like middlewares, or what if I put the add sub app process inside start up process? ). You can currently use a chain map instead of a list to organize startups and only the parent of a sub app will aware of it(parents know children but not vise versa). In addition, other frameworks like Django or Rails use class to describe their webapp(, which is already a graph by instinct). The instantiation of a class is actually an invocation of the runtime. |
The proposed graph-based solution is
|
Or, is there any way to insert a startup before the startup of the sub app? |
I don't follow. |
Yes, I can do everything before the calling, but the caller(intermediate app) may not be equipped with a from aiohttp import web
# the inner app
app_a = web.Application()
async def index_of_a(request):
return web.Response(text=request.app['db'])
app_a.router.add_get('/', index_of_a)
# the setup process of app a should be controlled inside
# the startup of app b
async def setup_db_of_inner_app(app):
app_a['db'] = app['db']
app_b = web.Application()
# a as the nested app of b
app_b.on_startup.append(setup_db_of_inner_app)
app_b.add_subapp('/a', app_a)
# the outer app
app_c = web.Application()
# take care of the setup of app b
async def db_of_app_a_and_setup_db_of_intermediate_app(app):
# first setup the outer app
app['db'] = 'the db'
# then the intermediate, namely the `direct child` of outer app
app_b['db'] = app['db']
app_c.on_startup.append(db_of_app_a_and_setup_db_of_intermediate_app)
app_c.add_subapp('/b', app_b)
web.run_app(app_c) That's what I mean by def plugin_app(app, prefix, nested):
async def set_db(a):
nested['db'] = a['db']
app.on_startup.append(set_db)
app.add_subapp(prefix, nested) |
Actually I've found something more interesting. In the previous comment I made the mistake again but I didn't think it further, but now I think it's to be taken into consideration. from aiohttp import web
def plugin_app(app, prefix, nested):
async def set_db(a):
print(a.name)
nested['db'] = a['db']
app.on_startup.append(set_db)
app.add_subapp(prefix, nested)
# the inner app
app_a = web.Application()
app_a.name = 'a'
async def index_of_a(request):
return web.Response(text=request.app['db'])
app_a.router.add_get('/', index_of_a)
app_b = web.Application()
app_b.name = 'b'
app_c = web.Application()
app_c.name = 'c'
app_d = web.Application()
app_d.name = 'd'
plugin_app(app_b, '/a', app_a)
plugin_app(app_c, '/b', app_b)
plugin_app(app_d, '/c', app_c)
app_d['db'] = 'db'
web.run_app(app_d) and from aiohttp import web
def plugin_app(app, prefix, nested):
async def set_db(a):
print(a.name)
a['db'] = app['db']
nested.on_startup.append(set_db)
app.add_subapp(prefix, nested)
# the inner app
app_a = web.Application()
app_a.name = 'a'
async def index_of_a(request):
return web.Response(text=request.app['db'])
app_a.router.add_get('/', index_of_a)
app_b = web.Application()
app_b.name = 'b'
app_c = web.Application()
app_c.name = 'c'
app_d = web.Application()
app_d.name = 'd'
plugin_app(app_b, '/a', app_a)
plugin_app(app_c, '/b', app_b)
plugin_app(app_d, '/c', app_c)
app_d['db'] = 'db'
web.run_app(app_d) The only difference is how I initialize the two apps.
but the later yields
I wonder how the order is controlled, by which I mean a kind of graph. Maybe I will still stick to the graph based solution. @asvetlov |
Both snippets are identical and both generate KeyError exception |
Just push |
What if I write an app to be shared as a nested app among several projects and it has subapps and these subapps should have a |
Is it an abstract question, do you have a real example? Django has only one level of application nesting, Flask's blueprints cannot nested too. |
Actually I write a restful route table first. Then I have from aiohttp import web
def plugin_app(app, prefix, nested):
async def set_db(a):
print(a.name)
a['db'] = app['db']
nested.on_startup.append(set_db)
app.add_subapp(prefix, nested)
# the inner app
app_a = web.Application()
app_a.name = 'a'
async def index_of_a(request):
return web.Response(text=request.app['db'])
app_a.router.add_get('/', index_of_a)
app_b = web.Application()
app_b.name = 'b'
async def set_db(app):
print(app.name)
app['db'] = 'db'
app_b.on_startup.append(set_db)
plugin_app(app_b, '/a', app_a)
web.run_app(app_b) it works but fails if I put a further nested app. Then I leave the issue. |
Fixed by #2949 |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a [new issue] for related bugs. |
Long story short
I've read your answer in #2413 (raised in #2412 ).
The solution (
subapp['db'] = mainapp['db']
) does not work when it comes to nested subapps.For example, if I have to build an app A, which have some subapp B and I need to pass the db connection from A to B, which can be done in that behavior. But, when I need to nest app A as a subapp to C, another app, and how should I pass db from C to A and to B. Clearly, the sharing between A and B exists before that between C and A, when A does not know the existence of db (which is even set inside startup) and C should also know nothing about the inner structure of A. A more complicated mechanism should be provided.
Expected behaviour
A more complicated solution.
Actual behaviour
Too simple to solve the problem.
Steps to reproduce
My solution
I'm trying to solve the problem by making the db become a
promise
(or a monad, which makes more sense about the side effect of the main app on the sub app ?).While flask provides a
g
so I can share the db between different apps (with in the same request), will you consider adding a same mechanism (or a monadic implementation if your consider about the implicitside effect
introduced byg
), since not only the db is shared(more data should be shared?).The text was updated successfully, but these errors were encountered: