Skip to content

Stop for qos timer#9903

Merged
macfarla merged 9 commits intobesu-eth:mainfrom
macfarla:stop-for-qos-timer
Mar 2, 2026
Merged

Stop for qos timer#9903
macfarla merged 9 commits intobesu-eth:mainfrom
macfarla:stop-for-qos-timer

Conversation

@macfarla
Copy link
Copy Markdown
Contributor

PR description

QosTimer.java Added a volatile boolean stopped flag and a stop() method that cancels the vertx timer. The timer handler and resetTimerHandler() both check the flag before rescheduling, and resetTimer() returns early if stopped.

EngineCallListener.java Added default void stop() {} so all listeners can be stopped without breaking existing implementations.

EngineQosTimer.java stop() delegates to qosTimer.stop().
ExecutionEngineJsonRpcMethod.java — Added getEngineCallListener() getter to expose the protected field.
EngineJsonRpcService.java — stop() now calls stopEngineCallListener() first, which finds any ExecutionEngineJsonRpcMethod in the methods map and calls stop() on its listener. This cancels the QosTimer before the HTTP server is
closed, allowing the vertx eventloop to shut down cleanly.

The shutdown sequence now works:

  1. Runner.stopServices() calls engineJsonRpc.stop()
  2. EngineJsonRpcService.stop() cancels the EngineQosTimer via the methods map
  3. Then closes the HTTP server
  4. Runner.stop() calls vertx.close() which now succeeds because the timer is no longer rescheduling
  5. Process exits cleanly

Fixed Issue(s)

Before this PR, running besu locally would frequently not shutdown cleanly eg besu this, and continues logging the engine message every 120 seconds, and I needed to kill the process.

  2026-02-26 17:20:47.757+1000 | BesuCommand-Shutdown-Hook | INFO  | DNSDaemon | Stopping DNSDaemon for enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net
  2026-02-26 17:20:47.760+1000 | BesuCommand-Shutdown-Hook | INFO  | EthProtocolManager | Stopping eth Subprotocol.
  2026-02-26 17:20:52.213+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected
  2026-02-26 17:21:02.765+1000 | BesuCommand-Shutdown-Hook | ERROR | DefaultP2PNetwork | DefaultP2PNetwork did not shutdown cleanly: some internal services failed to fully terminate.
  2026-02-26 17:21:02.767+1000 | BesuCommand-Shutdown-Hook | INFO  | EthProtocolManager | eth Subprotocol stopped.
  2026-02-26 17:21:02.767+1000 | BesuCommand-Shutdown-Hook | INFO  | NetworkRunner | Network stopped.
  2026-02-26 17:21:02.768+1000 | BesuCommand-Shutdown-Hook | INFO  | AutoTransactionLogBloomCachingService | Shutting down Auto transaction logs caching service.
  2026-02-26 17:21:02.768+1000 | BesuCommand-Shutdown-Hook | INFO  | NatService | No NAT environment detected so no service could be stopped
  2026-02-26 17:22:52.215+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected
  2026-02-26 17:24:52.219+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected
  2026-02-26 17:26:52.221+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected
  2026-02-26 17:28:52.224+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected

after this PR, besu logs this and successfully stops:

2026-02-26 19:16:04.403+1000 | EthScheduler-Timer-0 | INFO  | PivotSelectorFromSafeBlock | Waiting for consensus client, this may be because your consensus client is still syncing
2026-02-26 19:17:04.211+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected
2026-02-26 19:17:04.443+1000 | EthScheduler-Timer-0 | INFO  | PivotSelectorFromSafeBlock | Waiting for consensus client, this may be because your consensus client is still syncing
2026-02-26 19:18:04.486+1000 | EthScheduler-Timer-0 | INFO  | PivotSelectorFromSafeBlock | Waiting for consensus client, this may be because your consensus client is still syncing
2026-02-26 19:19:04.216+1000 | vert.x-eventloop-thread-0 | WARN  | EngineQosTimer | Execution engine not called in 120 seconds, consensus client may not be connected
2026-02-26 19:19:04.538+1000 | EthScheduler-Timer-0 | INFO  | PivotSelectorFromSafeBlock | Waiting for consensus client, this may be because your consensus client is still syncing
^C2026-02-26 19:19:10.125+1000 | BesuCommand-Shutdown-Hook | INFO  | DefaultSynchronizer | Stopping synchronizer
2026-02-26 19:19:10.126+1000 | BesuCommand-Shutdown-Hook | INFO  | SnapSyncDownloader | Stopping sync
2026-02-26 19:19:10.126+1000 | BesuCommand-Shutdown-Hook | INFO  | NetworkRunner | Stopping Network.
2026-02-26 19:19:10.136+1000 | BesuCommand-Shutdown-Hook | INFO  | EthProtocolManager | Stopping eth Subprotocol.
2026-02-26 19:19:10.173+1000 | BesuCommand-Shutdown-Hook | INFO  | EthProtocolManager | eth Subprotocol stopped.
2026-02-26 19:19:10.173+1000 | BesuCommand-Shutdown-Hook | INFO  | NetworkRunner | Network stopped.
2026-02-26 19:19:10.173+1000 | BesuCommand-Shutdown-Hook | INFO  | AutoTransactionLogBloomCachingService | Shutting down Auto transaction logs caching service.
2026-02-26 19:19:10.174+1000 | BesuCommand-Shutdown-Hook | INFO  | NatService | No NAT environment detected so no service could be stopped

Thanks for sending a pull request! Have you done the following?

  • Checked out our contribution guidelines?
  • Considered documentation and added the doc-change-required label to this PR if updates are required.
  • Considered the changelog and included an update if required.
  • For database changes (e.g. KeyValueSegmentIdentifier) considered compatibility and performed forwards and backwards compatibility tests

Locally, you can run these tests to catch failures early:

  • spotless: ./gradlew spotlessApply
  • unit tests: ./gradlew build
  • acceptance tests: ./gradlew acceptanceTest
  • integration tests: ./gradlew integrationTest
  • reference tests: ./gradlew ethereum:referenceTests:referenceTests
  • hive tests: Engine or other RPCs modified?

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Copilot AI review requested due to automatic review settings February 26, 2026 10:14
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a shutdown issue where the EngineQosTimer continued running after Besu initiated shutdown, preventing the process from exiting cleanly. The fix introduces a stop mechanism that cancels the QoS timer before closing the HTTP server, allowing the vertx event loop to terminate properly.

Changes:

  • Added a stop() method to the QosTimer that sets a volatile stopped flag and cancels the vertx timer
  • Introduced a default stop() method in the EngineCallListener interface for backward compatibility
  • Modified EngineJsonRpcService to stop the EngineCallListener before shutting down the HTTP server

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
QosTimer.java Added volatile stopped flag and stop() method to cancel timer and prevent rescheduling
EngineCallListener.java Added default stop() method to interface
EngineQosTimer.java Implemented stop() by delegating to underlying QosTimer
ExecutionEngineJsonRpcMethod.java Added getter to expose engineCallListener field
EngineJsonRpcService.java Added stopEngineCallListener() to cancel timer before HTTP server shutdown
CHANGELOG.md Added entry documenting the fix

Copy link
Copy Markdown
Contributor

@usmansaleem usmansaleem left a comment

Choose a reason for hiding this comment

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

LGTM - I would add a quick test for QosTimer.stop() though (that it prevents rescheduling).

macfarla added 4 commits March 2, 2026 15:27
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
@macfarla macfarla enabled auto-merge (squash) March 2, 2026 19:51
@macfarla macfarla merged commit 833e0ca into besu-eth:main Mar 2, 2026
46 checks passed
@macfarla macfarla deleted the stop-for-qos-timer branch March 3, 2026 05:53
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.

3 participants