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

Issue #7344 - wait for forked jetty process #7374

Merged

Conversation

janbartel
Copy link
Contributor

Closes #7344

Change org.eclipse.jetty.server.ShutdownMonitor to add a new command: pid. This reports the process id of the running jetty process. Changed the org.eclipse.jetty.maven.plugin.JettyStopMojo to first send this command to the running jetty process to obtain its id before sending a stop command. If the pid is retrievable, the stop mojo will wait (a configurable amount of time) for the jetty process to exit before terminating. If the pid is bad or missing, then the stop mojo falls back to it's previous behaviour of waiting a configurable amount of time to receive the Stopped message from the jetty process before terminating.

@janbartel janbartel requested review from gregw, sbordet and lorban January 13, 2022 00:32
@janbartel janbartel self-assigned this Jan 13, 2022
@janbartel janbartel requested a review from olamy January 14, 2022 00:33
{
getLog().error(e);
out.write(command.getBytes());
out.flush();
Copy link
Contributor

Choose a reason for hiding this comment

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

No, TCP is not very friendly with open/write/close.
You should always read to have a confirmation that the other peer received the data (even if it's only reading -1).
The other machine could be overloaded, so SYN+PSH+FIN may be received by the recipient at OS level (but not yet at application level), but because the machine is overloaded timeouts may happen, so the OS decides to RST back to the sender, which has already closed.
The net result is that the sender does not know that something went wrong, the recipient never received the data at the application level, and everything went into /dev/null.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the sender is interested in getting confirmation from the remote jetty, then they configure a non-zero stopWait timeout, in which case we set the socket soTimeout and read from it to get the "Shutting down" message. Alternatively, if we have been able to obtain the pid, we send the message and then wait up to stopWait seconds on the process itself to stop. So in either case, there will be a wait for either a response message, or the process to die. If no wait is configured, then we don't wait for any response, we just send the message and exit.

Copy link
Contributor

@sbordet sbordet Jan 17, 2022

Choose a reason for hiding this comment

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

You are assuming that the message you send reaches the other end. I'm saying that it may not.
Now, if you care whether the message reaches the other end, you should read, at least a -1.
If you don't care whether the message reaches the other end, then you may not read (like the code above), just don't assume that send() actually produces the results you want.
It's not about getting confirmation about the specific command.
It's about getting a confirmation that the message even arrived to the other process.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So @sbordet how long does the sender need to wait to read from the socket to ensure that the message was sent? The behaviour of the ShutdownMonitor is to stop jetty before replying with "Stopped" and exiting. In the case where the caller has not configured a stopWait time they do not want to wait until the socket is closed etc.

* org.eclipse.jetty.server.ShutdownMonitor.
*
*/
public class MockShutdownMonitor
Copy link
Contributor

Choose a reason for hiding this comment

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

Why can't we use ShutdownMonitor?
It should be possible because there are tests that use ShutdownMonitor directly and not a mock.
We really want to test the real ShutdownMonitor, not this mock class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sbordet I'm not interested in testing ShutdownMonitor - we have other tests for that ;). The unit test it relates to is of the JettyStopMojo - all I want to do is to test the behaviour of the JettyStopMojo, and for that I need to control the behaviour of the ShutdownMonitor and its ShutdownMonitorRunnable. I can't do that by subclassing because ShutdownMonitor is effectively not extensible, hence the mocks.

Copy link
Contributor

Choose a reason for hiding this comment

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

I made ShutdownMonitor.start() and stop() public and I can rewrite these tests using directly ShutdownMonitor without 200 lines of mock code that must to be bug-free and maintained.
I'd prefer to fix ShutdownMonitor than adding a mock for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sbordet I have changed the final test testStopWait to talk to the real ShutdownMonitor. None of the other tests can use the real class because I need to test failure/fallback modes, and ShutdownMonitor is unsubclassable (private no-args constructor).

if (handle.isAlive())
{
handle = future.get(stopWait, TimeUnit.SECONDS);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think this block is correct.
future.get(wait, unit) throws TimeoutException if the time elapses, but the code seems to hint something like "if timeout and still alive, do something", so the "do something" will be skipped.

Have you considered using ProcessHandle.destroy[Forcibly]() if the timeout expires?
Perhaps along with CompletableFuture.orTimeout()?

Copy link
Contributor Author

@janbartel janbartel Jan 14, 2022

Choose a reason for hiding this comment

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

@sbordet this would be a behaviour change of the JettyStopMojo: it has always just made a best effort to stop the remote jetty, waiting up to the configured time to get an acknowledgement from jetty that it is shutting down before giving up. I suppose we could add a new configuration option to forcibly destroy the process after the timeout expires, but I think that might be in another issue.

Signed-off-by: Jan Bartel <[email protected]>
@janbartel janbartel requested a review from sbordet January 15, 2022 00:07
* org.eclipse.jetty.server.ShutdownMonitor.
*
*/
public class MockShutdownMonitor
Copy link
Contributor

Choose a reason for hiding this comment

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

I made ShutdownMonitor.start() and stop() public and I can rewrite these tests using directly ShutdownMonitor without 200 lines of mock code that must to be bug-free and maintained.
I'd prefer to fix ShutdownMonitor than adding a mock for it.

Signed-off-by: Jan Bartel <[email protected]>
@janbartel janbartel requested a review from sbordet January 18, 2022 03:39
@janbartel
Copy link
Contributor Author

@sbordet latest release has gone out - can you now approve this pr?

Copy link
Contributor

@sbordet sbordet left a comment

Choose a reason for hiding this comment

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

@janbartel a few suggested fixes have not been addressed (e.g. javadocs, semicolons, unnecessary types, etc.)?

@janbartel janbartel requested a review from sbordet February 10, 2022 22:24
@joakime joakime changed the title Jetty 10.0.x 7344 wait for forked jetty process Issue #7344 - wait for forked jetty process Feb 14, 2022
@janbartel janbartel merged commit 0b33877 into jetty-10.0.x Feb 21, 2022
@janbartel janbartel deleted the jetty-10.0.x-7344-wait-for-forked-jetty-process branch February 21, 2022 12:46
@joakime joakime added this to the 12.0.x milestone Feb 24, 2022
joakime pushed a commit that referenced this pull request Feb 25, 2022
* Issue #7344 Make plugin wait for forked jetty process to stop

Signed-off-by: Jan Bartel <[email protected]>
(cherry picked from commit 0b33877)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incompatible with jacoco due to shutdown race condition
5 participants