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

RSDK-5881 Add Stoppable class #186

Merged
merged 4 commits into from
Dec 6, 2023

Conversation

benjirewis
Copy link
Member

@benjirewis benjirewis commented Nov 29, 2023

RSDK-5881

Adds a Stoppable class with a purely virtual stop method from which stoppable resources should inherit.

@benjirewis benjirewis marked this pull request as ready for review November 29, 2023 16:48
@benjirewis benjirewis requested a review from a team as a code owner November 29, 2023 16:48
@benjirewis benjirewis requested review from purplenicole730 and removed request for a team November 29, 2023 16:48
Copy link
Member

@stuqdog stuqdog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple minor things but this looks great, thanks for hopping on it so fast!

src/viam/sdk/robot/service.cpp Outdated Show resolved Hide resolved
src/viam/sdk/resource/resource.cpp Outdated Show resolved Hide resolved
src/viam/sdk/resource/resource.cpp Outdated Show resolved Hide resolved
src/viam/sdk/resource/resource.hpp Outdated Show resolved Hide resolved
src/viam/sdk/resource/resource.hpp Outdated Show resolved Hide resolved
src/viam/sdk/robot/service.cpp Outdated Show resolved Hide resolved
src/viam/examples/modules/tflite/main.cpp Outdated Show resolved Hide resolved
src/viam/sdk/services/mlmodel/mlmodel.hpp Outdated Show resolved Hide resolved
src/viam/examples/modules/tflite/main.cpp Outdated Show resolved Hide resolved
src/viam/sdk/resource/resource.cpp Outdated Show resolved Hide resolved
Copy link
Member

@stuqdog stuqdog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

Copy link
Member

@acmorrow acmorrow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is very close, but I think stop in TFLite was actually reachable and should continue to be.

@@ -133,7 +134,7 @@ ::grpc::Status ModuleService_::ReconfigureResource(

// if the type isn't reconfigurable by default, replace it
try {
res->stop();
Stoppable::stop_if_stoppable(res);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So ... am I reading this right that the only way to reach this code is if reconfigure threw an exception that did not derive from std::exception?

Also,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds correct; my understanding of that code is to call stop if the resource does not actually implement a reconfigure method (and throws some exception that's not std::exception?) and reconstruct the resource instead of reconfiguring.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes me wonder if we need a Reconfigurable mixin, much like Stoppable. The status quo is that all Resource implementations must implement reconfigure, but with an escape hatch where throwing an exception (but only one that doesn't derive from std::exception!) is the signal that the resource doesn't actually support reconfiguration. I'm not sure I'm too keen on that design. Maybe a ticket is in order?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think a Reconfigurable class is better. Filed https://viam.atlassian.net/browse/RSDK-5967.

@@ -194,7 +195,7 @@ ::grpc::Status ModuleService_::RemoveResource(
}

try {
res->stop();
Stoppable::stop_if_stoppable(res);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and above, in the past, if the implementation object inside a module had an override of Resource::stop, it'd get called here. Now, it won't, unless the implementation object explicitly derives from Stoppable. That seems like a breaking change for modules.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct if I'm understanding you.

Now, it won't, unless the implementation object explicitly derives from Stoppable. That seems like a breaking change for modules.

I actually thought this was desirable, and that we were OK with the sort of "opt-in" behavior here of "if you want your resource to be stopped on modular removal or StopAll, you must explictitly inherit Stoppable and override stop".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm trying to get at is that if you have an existing resource implemented (presumably as a module), it almost certainly has a stop method defined, because it had to: Resource::stop was pure virtual so you had to provide a definition.

And, that definition had paths that called it: from ModuleService::reconfigureResource if a non-std::exception exception was thrown, and from ModuleService::RemoveResource. And the steps taken in that stop may have been important.

After this change, the resource defined in the module will still have a stop method, but it won't be Resource::stop and it won't be Stoppable::stop: it will just be the stop method of the resource. None of the management code here can ever cause that stop to be invoked.

So it is something of a breaking change, in that if the implementation of your module was relying on stop in order to manage shutdown, it won't be getting called anymore. As an example, you needed to make changes to the TFLite module here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it is something of a breaking change, in that if the implementation of your module was relying on stop in order to manage shutdown, it won't be getting called anymore. As an example, you needed to make changes to the TFLite module here.

Yeah it's a good point, and after discussing offline, I think we should have MLModelServiceTFLite : public Stoppable for now despite Stoppable now modeling both gRPC stop methods and stop (acting as a "cleanup" method) for modular resources.

@@ -71,19 +71,16 @@ class MLModelServiceTFLite : public vsdk::MLModelService {
// here. It should be safe to tear down all state
// automatically without needing to wait for anything more to
// drain.
close();
Copy link
Member

@acmorrow acmorrow Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comment over in module/service.cpp, but I suspect the status quo is that the stop method was in fact reachable from ModuleService_, probably from RemoveResource, and maybe from ReconfigureResource under some circumstances. I wonder if the move here is to leave this as close, and have MLModelServiceTFLite derive from Stoppable instead. It's a little wrong, in that it doesn't model a "stop GRPC", but at least it keeps the stop that the ModuleService and RobotService want to call on resources wired into the stopp-y behavior of this type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we try putting this back to having a stop method but having MLModelServiceTFLite derive from Stoppable? I think that would mean that the stop_if_stoppable calls from ModuleService_ would actually do the right thing, and then we wouldn't need to introduce the new close concept.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! Derived MLModelServiceTFLite from Stoppable and maintained its stop implementation present on main.

Copy link
Member

@acmorrow acmorrow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM except that 1) I think the TFLite service should be made to derive from Stoppable rather than introducing the new close stuff, please see my inline comments to that effect, and 2) I think there is a subtle breaking change here, which maybe needs some messaging so module implementers know what to do.

@@ -133,7 +134,7 @@ ::grpc::Status ModuleService_::ReconfigureResource(

// if the type isn't reconfigurable by default, replace it
try {
res->stop();
Stoppable::stop_if_stoppable(res);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes me wonder if we need a Reconfigurable mixin, much like Stoppable. The status quo is that all Resource implementations must implement reconfigure, but with an escape hatch where throwing an exception (but only one that doesn't derive from std::exception!) is the signal that the resource doesn't actually support reconfiguration. I'm not sure I'm too keen on that design. Maybe a ticket is in order?

@@ -194,7 +195,7 @@ ::grpc::Status ModuleService_::RemoveResource(
}

try {
res->stop();
Stoppable::stop_if_stoppable(res);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm trying to get at is that if you have an existing resource implemented (presumably as a module), it almost certainly has a stop method defined, because it had to: Resource::stop was pure virtual so you had to provide a definition.

And, that definition had paths that called it: from ModuleService::reconfigureResource if a non-std::exception exception was thrown, and from ModuleService::RemoveResource. And the steps taken in that stop may have been important.

After this change, the resource defined in the module will still have a stop method, but it won't be Resource::stop and it won't be Stoppable::stop: it will just be the stop method of the resource. None of the management code here can ever cause that stop to be invoked.

So it is something of a breaking change, in that if the implementation of your module was relying on stop in order to manage shutdown, it won't be getting called anymore. As an example, you needed to make changes to the TFLite module here.

@@ -71,19 +71,16 @@ class MLModelServiceTFLite : public vsdk::MLModelService {
// here. It should be safe to tear down all state
// automatically without needing to wait for anything more to
// drain.
close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we try putting this back to having a stop method but having MLModelServiceTFLite derive from Stoppable? I think that would mean that the stop_if_stoppable calls from ModuleService_ would actually do the right thing, and then we wouldn't need to introduce the new close concept.

@benjirewis benjirewis merged commit 25b38e2 into viamrobotics:main Dec 6, 2023
2 checks passed
@benjirewis benjirewis deleted the stoppable-resource branch December 6, 2023 00:25
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

Successfully merging this pull request may close these issues.

4 participants