Graceful Shutdown of RocketMQ Consumer in Spring Applications
The article recounts a production incident caused by an ungraceful RocketMQ consumer shutdown, analyzes the root cause involving Spring's bean destruction order and ShutdownHook behavior, and presents two solutions—using the official Spring‑Boot starter with SmartLifecycle or handling ContextClosedEvent—to achieve orderly termination.
On a late night in December 2018, the author encountered an alarm after clicking the release button, discovering a persistence exception indicating that the data source was already closed:
org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.alibaba.druid.pool.DataSourceClosedException: dataSource already closedFurther investigation revealed that a RocketMQ consumer, registered with a ShutdownHook and set to the highest priority, threw an exception when the application was terminated because the consumer was not notified of the traffic cut‑off.
The consumer’s shutdown logic relied on an acknowledgment mechanism, so messages would be retried and no business data was lost, but the abrupt termination was still undesirable.
Initially, the author attempted to control bean destruction order using depend‑on in XML configuration, manually adding dependencies between beans, which worked for a single project but proved unmanageable across many services.
Later, the author discovered the official spring-boot-starter-rocketmq which implements the SmartLifecycle interface. Its start method runs after all beans are initialized, and its stop method executes before bean destruction, providing a clean way to shut down the consumer.
Reviewing Spring’s shutdown process in AbstractApplicationContext.doClose showed that before destroying beans, Spring closes lifecycle beans and publishes a ContextClosedEvent . Implementing SmartLifecycle leverages this sequence.
Finally, the author proposes two options for the team: replace existing consumers with the official starter (high migration cost) or encapsulate a ContextClosedEvent listener to provide a reusable graceful‑shutdown component for business services.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.