-
Notifications
You must be signed in to change notification settings - Fork 43
feat: add graceful VM shutdown on exit signals #316
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
feat: add graceful VM shutdown on exit signals #316
Conversation
Reviewer's GuideThe PR refactors signal-based termination to use a channel-driven exit handler, replacing direct os.Exit calls with controlled shutdown logic so that the VM’s Stop method is invoked before process termination. Sequence Diagram for Graceful VM Shutdown via Exit ChannelsequenceDiagram
actor User/OS
participant SH as "Signal Handler (util.SetupExitSignalHandling)"
participant EC as "exitChan"
participant MG as "Main Goroutine (vfkit)"
participant REH as "Registered Exit Handler"
participant VM as "VirtualMachine (vfVM)"
User/OS->>SH: Termination Signal (e.g. SIGINT, SIGTERM)
SH->>EC: Send termination event on channel
MG->>EC: Receives termination event from channel
Note over MG: Initiates graceful shutdown sequence
alt Graceful Shutdown Process
MG->>REH: Runtime (or equivalent mechanism) invokes registered handler
REH->>VM: Stop()
VM-->>REH: VM Stopped successfully
end
Note over MG: Process exits cleanly
Class Diagram: Signal Handling and VM Control ComponentsclassDiagram
class MainApp {
<<Go Application>>
+runVFKit(vmConfig *config.VirtualMachine, opts *cmdline.Options) error
#vfVM: VirtualMachine
#exitChan: chan os.Signal
}
class Util {
<<Go Package>>
+SetupExitSignalHandling(exitChan chan os.Signal) void
+RegisterExitHandler(handler func()) void
}
class VirtualMachine {
+Stop() error
}
MainApp --> Util : uses signal handling utilities
MainApp --> VirtualMachine : controls lifecycle
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
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.
Hey @vyasgun - I've reviewed your changes - here's some feedback:
- Consider making exitChan buffered or using a non‐blocking select when sending to it to avoid blocking the signal handler goroutine if no receiver is ready.
- setupExitSignalHandling should guard against a nil exitChan (e.g. by checking before sending) to prevent deadlocks when tests pass nil.
- Rather than launching a separate goroutine in main, you could use util.RegisterExitHandler to register the VM stop logic and keep all shutdown handlers in one place.
Here's what I looked at during the review
- 🟢 General issues: all looks good
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
4f88261 to
c42e449
Compare
|
@sourcery-ai review |
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.
Hey @vyasgun - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟢 General issues: all looks good
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
cmd/vfkit/main.go
Outdated
| if err != nil { | ||
| log.Error(err) | ||
| } | ||
| }) |
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 don’t think we want to always run vfVM.Stop() in all cases when we exit vfkit.
As Nir summarized, there are (at least) 3 ways to exit vfkit
- guest stops and vfkit exits
- the REST API is used to stop/hard stop the VM
- a signal is sent to the vfkit process
It’s only for 3) that we want to try to run vfVM.Stop(), ie run it somehow here
Lines 42 to 48 in b67809f
| for sig := range sigChan { | |
| log.Printf("captured %v, calling exit handlers and exiting..", sig) | |
| ExecuteExitHandlers() | |
| if doExit { | |
| os.Exit(1) | |
| } | |
| } |
ExecuteExitHandler/os.Exit(), but instead let the VM stop, and then the cleanup at exit for 3) can also be done by this code: Line 34 in b67809f
| defer util.ExecuteExitHandlers() |
For 3), maybe we also need to do hardstop after a timeout if the VM does not exit in a reasonable time?
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 updated the PR so that there is a channel which captures when exitHandlers are executing and doExit is set. Upon receiving the signal, it will RequestStop the VM and a hardstop if the state of the vm doesn't change to Stopped after 5 seconds.
c42e449 to
d6a65a5
Compare
|
@sorcery-ai summary |
pkg/util/exithandler.go
Outdated
| // When one of these signals is received, all the registered exit handlers will be invoked. | ||
| // It is possible to prevent the program from exiting by setting the doExit param to false (used for testing) | ||
| func setupExitSignalHandling(doExit bool) { | ||
| func setupExitSignalHandling(exitChan chan bool, doExit bool) { |
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.
An alternative to this exitChan approach would be to pass a handler func() similar to what is done with RegisterExitHandler. But both approaches are fine, mentioning it here for completeness, changes are not required.
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 changed the code so it accepts a shutdown function and executes it. This makes testing also easier as I can provide a test implementation of the shutdown func
d6a65a5 to
d424730
Compare
cfergeau
left a comment
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.
Apart from the ExecuteExitHandler discussion, this looks good to me.
920d736 to
3597a2d
Compare
Replace os.Exit() with shutdown func to allow proper VM cleanup. VM now stops gracefully with RequestStop() before forcing termination.
3597a2d to
8297bfc
Compare
cfergeau
left a comment
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.
/lgtm
/approve
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: cfergeau The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Replace os.Exit() with channel-based shutdown to allow proper VM cleanup.
VM now stops gracefully with RequestStop() before forcing termination.
Fixes: #284
Summary by Sourcery
Refactor signal exit handling to notify the main goroutine via a channel instead of calling os.Exit directly to allow graceful VM shutdown.
Bug Fixes:
Enhancements:
Tests:
Summary by Sourcery
Register a channel-based exit handler to gracefully stop the VM on termination signals instead of abruptly exiting
Bug Fixes:
Enhancements:
Tests: