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

Cross-platform clean shutdown mechanism #767

Merged
merged 4 commits into from
Apr 8, 2020

Conversation

dcoutts
Copy link
Contributor

@dcoutts dcoutts commented Apr 7, 2020

Cross-platform clean shutdown support with --shutdown-ipc FD flag

Fixes #726

On Windows there is no standard reliable mechanism to politely ask a process to stop. There is only the brutal TerminateProcess. Using that by default is not great since it means the node always has to revalidate its chain DB on startup.

This adds an ad-hoc mechainsim that Daedalus can use to reliably shut down the node process. The --shutdown-ipc flag takes the FD of the read end of an inherited pipe. If provided, the node will monitor that pipe when when the write end of the pipe is closed then the node will initiate a clean shutdown. So Daedalus can explicitly terminate the node by closing the write end of the pipe. If Daedalus terminates uncleanly then the pipe will also be closed and the node will also shut down.

Although this mechanism is needed for Windows, it is also cross-platform so it can be used by Daedalus across all platforms.

@dcoutts dcoutts requested review from Jimbo4350 and rvl April 7, 2020 09:55
Copy link
Contributor

@rvl rvl left a comment

Choose a reason for hiding this comment

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

Looks good. Once this is merged I will change cardano-wallet to also use a FD other than stdin.
I think it needs changes to work on Windows though.

@@ -249,6 +252,15 @@ parseValidateDB =
<> help "Validate all on-disk database files"
)

parseShutdownIPC :: Parser (Maybe Fd)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this will compile on Windows because it's HANDLE there. Perhaps use Int here and sort out the rest when it's time to use fdToHandle.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

GHC uses the MS C lib on Windows which does actually handle these Fds.

where
waitForEOF :: IO ()
waitForEOF = do
hnd <- IO.fdToHandle fd
Copy link
Contributor

Choose a reason for hiding this comment

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

This will need some CPP for Windows.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same here. Surprisingly this is not Unix specific code.

| otherwise -> throwIO e

Right _ ->
throwIO $ IO.userError "--shutdown-ipc FD does not expect input"
Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea. Reporting an error in this case is probably more sensible than consuming the input.

withShutdownHandler :: NodeProtocolMode -> Tracer IO String -> IO () -> IO ()
withShutdownHandler (RealProtocolMode NodeCLI{shutdownIPC = Just (Fd fd)})
tracer action =
race_ waitForEOF action
Copy link
Contributor

Choose a reason for hiding this comment

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

Will this need application of the forkIO/MVar hack to avoid deadlocking on Windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes you're right. Sigh. Because this uses cancel on the left action when the right one finishes, and that will never complete...

@dcoutts dcoutts force-pushed the dcoutts/issue-726-windows-clean-shutdown branch from ca9fef4 to 8fe713d Compare April 7, 2020 15:58
@dcoutts dcoutts requested a review from rvl April 7, 2020 16:53
dcoutts added 3 commits April 7, 2020 19:26
Otherwise every time we add/remove/change fields in these records then a
dozen places in the code need updating.

Also add a TODO about the structure of these types. They now share
nothing but this is really too extreme, as demonstrated by the places
that this patch touches. There are a lot of places where we extract the
same information for both mock and real modes. So we should share the
things that are always the same.
Fixes #726

On Windows there is no standard reliable mechanism to politely ask a
process to stop. There is only the brutal TerminateProcess. Using that
by default is not great since it means the node always has to revalidate
its chain DB on startup.

This adds an ad-hoc mechainsim that Daedalus can use to reliably shut
down the node process. The --shutdown-ipc flag takes the FD of the read
ebd of an inherited pipe. If provided, the node will monitor that pipe
when when the write end of the pipe is closed then the node will
initiate a clean shutdown. So Daedalus can explicitly terminate the node
by closing the write end of the pipe. If Daedalus terminates uncleanly
then the pipe will also be closed and the node will also shut down.

Although this mechanism is needed for Windows, it is also cross-platform
so it can be used by Daedalus across all platforms.
@dcoutts dcoutts force-pushed the dcoutts/issue-726-windows-clean-shutdown branch from 8fe713d to 45d2a06 Compare April 7, 2020 20:12
Copy link
Contributor

@rvl rvl left a comment

Choose a reason for hiding this comment

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

Looks great 👍

-- process itself terminated, then we initiate a clean shutdown.
--
withShutdownHandler :: NodeProtocolMode -> Tracer IO String -> IO () -> IO ()
withShutdownHandler (RealProtocolMode NodeCLI{shutdownIPC = Just (Fd fd)})
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

@Jimbo4350 Jimbo4350 left a comment

Choose a reason for hiding this comment

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

LGTM!

-> Consensus.TopLevelConfig blk
-> IO ()
createTracers npm' tr tracer cfg = do
case npm' of
RealProtocolMode (NodeCLI _ rNodeAddr _ runDBValidation) -> do
RealProtocolMode NodeCLI{nodeAddr, validateDB} -> do
Copy link
Contributor

Choose a reason for hiding this comment

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

So NamedFieldPuns are good to go, unlike what was being categorically told by people.

And yes, personally, they make complete sense here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. NamedFieldPuns are great. RecordWildcards is what makes some people grumpy.

@oneEdoubleD
Copy link
Contributor

oneEdoubleD commented Apr 8, 2020

I've ran some tests on the cardano-node executable and this looks good. Non-brutal shutdowns are leaving the clean file in state as expected, brutal shutdowns by killing the PID are not, and there were no deadlocks or issues re-starting the node.

Furthermore, integration tests are passing for non-brutal shutdowns working correctly.

@dcoutts
Copy link
Contributor Author

dcoutts commented Apr 8, 2020

bors merge

@iohk-bors
Copy link
Contributor

iohk-bors bot commented Apr 8, 2020

@iohk-bors iohk-bors bot merged commit c75d2f0 into master Apr 8, 2020
@iohk-bors iohk-bors bot deleted the dcoutts/issue-726-windows-clean-shutdown branch April 8, 2020 17:15
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request Apr 9, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request Apr 10, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request Apr 11, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request Apr 12, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request Apr 15, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request May 5, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
rvl added a commit to cardano-foundation/cardano-wallet that referenced this pull request May 29, 2020
This modifies the clean shutdown handler to use a FD from the command
line, rather than taking stdin.

It also makes the logic even simpler, as shown in
IntersectMBO/cardano-node#767

The command-line arguments are changed
from --shutdown-handler to --shutdown-ipc FD
so that they are identical to cardano-node.
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.

Cross-platform clean shutdown
5 participants