Skip to content
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

Run before_serving and while_serving hooks in order of registration #358

Open
FichteFoll opened this issue Sep 19, 2024 · 2 comments
Open

Comments

@FichteFoll
Copy link

FichteFoll commented Sep 19, 2024

I'm building an application where I want to intialize a few things and I am registering the while_serving and before_serving hooks in my create_app, i.e. the main prodedure that generates the application. Some of these hooks have dependencies on others, e.g. settings must be loaded & validated first, then the connection to the database is established and then I do some initialization based on the database. before_serving hooks are executed in order, so that is good.

However, because I want to register the database setup in a while_serving so that I can also easily and precisely release the database resources (registered in the same generator function) once the application shuts down, the FIFO registering of hooks isn't working anymore because all before_serving hooks are called first and only then are the while_serving hooks executed/iterated. For me, it would be ideal if they were instead executed in the order of their registration.

I haven't mentioned after_serving yet and that's because I don't actually use it currently, but if I were to I believe that the the same ordering should apply, i.e. "unload" while_serving hooks and after_serving hooks in the order they were registered.

The abstract example code that illustrates this problem is as follows:

    app.before_serving(check_settings)
    # Uses settings
    app.while_serving(init_db)
    # Uses database
    app.before_serving(exporter.init_metrics)  # fails because `init_db` is executed later

My current workaround, after splitting the init_db generator into two functions:

    app.before_serving(check_settings)
    # Uses settings
    app.before_serving(init_db)
    app.after_serving(uninit_db)
    # Uses database
    app.before_serving(exporter.init_metrics)
@FichteFoll
Copy link
Author

FichteFoll commented Sep 19, 2024

I just realized that you would probably want to unload the while_serving hooks in reverse order, much like a stack, which doesn't fare well with my proposal. This is not something that quart is currently doing, but it might be worth considering. The problem is that this makes determining the after serving hook order much harder.

@FichteFoll
Copy link
Author

FichteFoll commented Nov 6, 2024

Thinking about this again randomly, unwinding the stack in reverse order for unloading is actually quite reasonable, if you think of a while_serving exactly like I did in my workaround: splitting them into before_serving and after_serving.

Implementation-wise, you would use a single stack for all lifecycle hooks, i.e. before_saving, while_serving and after_serving, to honor their registration order. Then, when executing the before hooks you would also run the while hooks in order until they yield. When unwinding the application, you would iterate the stack in reverse order and execute the after_saving hooks as well as the second parts of the paused while_serving hooks. That would be predictable and not really complicated either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant