-
Notifications
You must be signed in to change notification settings - Fork 40
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
Decorator-based lifecycle hooks #1136
Conversation
52c946e
to
25e0a30
Compare
6469f1e
to
5953f1f
Compare
5953f1f
to
dcf00e2
Compare
How should we handle the checkpointing case? Is that |
Yeah, that's exactly right - I think we should add some more decorators to support more granular hooks, e.g. |
2e0efbd
to
cee016b
Compare
1f41c53
to
6ef7656
Compare
We'll run all of them, in the order they were defined! So you can have something like this @stub.cls()
class MyClass:
@build()
@enter()
def my_build(self):
print("this one runs during image build and container start")
@enter()
def my_enter(self):
print("this one runs during container start, after the previous one") |
EDIT: fixed these |
This doesn't currently support Given that this is new functionality I think it's OK to not support it for now – we can probably fix that in a later refactoring (there's some code we should share between cls and container_entrypoint) |
Demo on some examples: modal-labs/modal-examples#507 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great! Example looks much cleaner now.
method = synchronize_api(_method) | ||
web_endpoint = synchronize_api(_web_endpoint) | ||
asgi_app = synchronize_api(_asgi_app) | ||
wsgi_app = synchronize_api(_wsgi_app) | ||
build = synchronize_api(_build) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these synchronized btw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a similar question actually. I think it has something to do with how we want _PartialFunction.__get__
to return a Function
not a _Function
, which means we have to synchronize the _PartialFunction
class, which means we end up with internal and external versions of everything... I'm not entirely sure though.
This is obviously pretty complex and it would be nice to simplify it
Btw this passes all integration tests as well. I'm pretty happy with the decorator-based lifecycle hooks SDK, but I'm a bit annoyed how complex the implementation was. A lot of this stems from complexities in the |
Post-merge things I think would be nice to clean up:
None of this is super urgent since it doesn't rely on the server protocol and it keeps the SDK stable, so we could potentially hold off on some of it |
This adds
@build
,@enter
, and@exit
which are decorators you can apply to class methods to trigger lifecycle hooks. Also a bunch of general refactoring of_PartialFunction
code to support stacking decorators and generalize how we grab methods from user classes.Synopsis:
In the example above, the
my_enter
method will run both as a part of building the image, and as a part of every container initialization, showcasing the ability to stack decorators. This new syntax intends to solve both (1) an easier way to "auto-initialize" images (2) a more ergonomic replacement for most/all cases ofImage.run_function
.Big delta but a lot of it is tests. And we should be able to retire a bit of code later once we deprecate the "legacy" methods. I didn't add any deprecation warnings at this point since this is complex change so we might want to take our time and update docs and examples to verify that this approach is the right one.