Before Creating the Bug Report
Runtime platform environment
Ubuntu 22.04.5 LTS, Linux x86_64.
RocketMQ version
Branch: develop
Version: 5.5.1
Git commit id: e90303810a14
JDK Version
OpenJDK 8u502.
Describe the Bug
MessageRocksDBStorage creates a ScheduledExecutorService and registers a
periodic timer-WAL flush task in postLoad():
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(this::flushTimerWal, 5, 5, TimeUnit.MINUTES);
However, preShutdown() does not cancel the scheduled task or shut down the
scheduler. AbstractRocksDBStorage.reloadRocksdb() uses the existing
shutdown() followed by start() lifecycle. Because the same scheduler
remains active, every successful reload registers another periodic flush task
on the same executor.
This also leaves a non-daemon scheduler and its delayed task alive after the
RocksDB resources have been closed.
Steps to Reproduce
- Create a
MessageRocksDBStorage with a temporary MessageStoreConfig.
- Inspect its private scheduler as a
ScheduledThreadPoolExecutor using a
focused test or debugger. After construction, one periodic task is queued.
- Call
storage.shutdown().
- Inspect the scheduler again and observe that it is not shut down and that
its queue still contains one periodic task.
- Call
storage.start() to simulate the lifecycle used by
AbstractRocksDBStorage.reloadRocksdb().
- Call
storage.shutdown() and storage.start() once more.
- Inspect the scheduler after each start.
The affected code shows the following stable state transition:
| Lifecycle state |
Scheduler state |
Queued periodic tasks |
| After construction |
active |
1 |
| After first shutdown |
not shut down |
1 |
| After first start |
active |
2 |
| After second shutdown |
not shut down |
2 |
| After second start |
active |
3 |
What Did You Expect to See?
storage.shutdown() should cancel the periodic timer-WAL flush task and
shut down its scheduler.
- Each subsequent
start() should create one scheduler with exactly one
periodic flush task.
- A scheduled task should not access RocksDB resources after they have been
closed.
What Did You See Instead?
- The scheduler remains active after
storage.shutdown().
- The delayed periodic task remains queued after the RocksDB instance and its
options have been closed.
- Each shutdown/start reload adds another periodic flush task to the same
executor.
- The scheduled runnable directly accesses
db, flushOptions, and
timerCFHandle without a lifecycle guard. If it runs during shutdown, it can
access resources that are being closed or have already been cleared.
Additional Context
No response
Before Creating the Bug Report
I found a bug, not just asking a question, which should be created in GitHub Discussions.
I have searched the GitHub Issues and GitHub Discussions of this repository and believe that this is not a duplicate.
I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ.
Runtime platform environment
Ubuntu 22.04.5 LTS, Linux x86_64.
RocketMQ version
Branch:
developVersion:
5.5.1Git commit id:
e90303810a14JDK Version
OpenJDK 8u502.
Describe the Bug
MessageRocksDBStoragecreates aScheduledExecutorServiceand registers aperiodic timer-WAL flush task in
postLoad():However,
preShutdown()does not cancel the scheduled task or shut down thescheduler.
AbstractRocksDBStorage.reloadRocksdb()uses the existingshutdown()followed bystart()lifecycle. Because the same schedulerremains active, every successful reload registers another periodic flush task
on the same executor.
This also leaves a non-daemon scheduler and its delayed task alive after the
RocksDB resources have been closed.
Steps to Reproduce
MessageRocksDBStoragewith a temporaryMessageStoreConfig.ScheduledThreadPoolExecutorusing afocused test or debugger. After construction, one periodic task is queued.
storage.shutdown().its queue still contains one periodic task.
storage.start()to simulate the lifecycle used byAbstractRocksDBStorage.reloadRocksdb().storage.shutdown()andstorage.start()once more.The affected code shows the following stable state transition:
What Did You Expect to See?
storage.shutdown()should cancel the periodic timer-WAL flush task andshut down its scheduler.
start()should create one scheduler with exactly oneperiodic flush task.
closed.
What Did You See Instead?
storage.shutdown().options have been closed.
executor.
db,flushOptions, andtimerCFHandlewithout a lifecycle guard. If it runs during shutdown, it canaccess resources that are being closed or have already been cleared.
Additional Context
No response