When an application restarts during a release, running scheduled jobs are interrupted, which can cause incomplete data processing or inconsistent states. SchedulerX graceful shutdown lets running jobs complete before the application process exits.
How it works
When graceful shutdown is enabled, the application process intercepts shutdown signals and delays its exit until in-flight jobs finish, up to an optional timeout.
-
A shutdown signal is received (for example,
kill -15, a Spring Boot shutdown event, or an HTTP request). -
Running jobs and tasks continue executing based on the configured shutdown mode.
-
After all qualifying jobs complete or the timeout expires, the application process exits.
Graceful shutdown diagram

Prerequisites
Before you begin, make sure that you have:
-
SchedulerX client version 1.10.8 or later
Shutdown modes
SchedulerX supports two graceful shutdown modes for jobs running in standalone mode and distributed mode:
| Mode | Behavior | When to use |
|---|---|---|
WAIT_ALL (recommended) |
The application exits only after all jobs and tasks complete, including those in queue. | Every scheduled job must finish to maintain data consistency. |
WAIT_RUNNING |
The application exits after currently running jobs and tasks (with allocated threads) complete. Jobs and tasks in queue are dropped. | Queued jobs can be safely retried or skipped. |
Configure graceful shutdown
Add the following properties to your Spring Boot configuration:
# Shutdown mode: WAIT_ALL or WAIT_RUNNING
# Not configured by default (graceful shutdown is disabled).
spring.schedulerx2.graceShutdownMode=WAIT_ALL
# Maximum time (in seconds) to wait before forcing shutdown.
# Not configured by default (no timeout).
spring.schedulerx2.graceShutdownTimeout=10
# Enable the built-in HTTP shutdown endpoint. Default: false.
spring.schedulerx2.httpServerEnable=true
# Port for the HTTP shutdown endpoint. Default: 51886.
spring.schedulerx2.httpServerPort=51886
| Parameter | Description | Default |
|---|---|---|
spring.schedulerx2.graceShutdownMode |
Shutdown mode: WAIT_ALL or WAIT_RUNNING |
Not configured (disabled) |
spring.schedulerx2.graceShutdownTimeout |
Maximum wait time in seconds before the process is forcefully terminated | Not configured (no timeout) |
spring.schedulerx2.httpServerEnable |
Enable the HTTP shutdown endpoint | false |
spring.schedulerx2.httpServerPort |
Port for the HTTP shutdown endpoint | 51886 |
Set graceShutdownTimeout to a value appropriate for your longest-running job. Without a timeout, a stuck job can block the application from ever shutting down.
Trigger graceful shutdown
Choose one of the following methods to trigger graceful shutdown. Method 1 (kill -15) works for any Java application. Methods 2 and 3 provide HTTP-based alternatives.
Method 1: Send SIGTERM with kill -15
SchedulerX registers a JVM shutdown hook that intercepts SIGTERM. Send the signal to the application process:
kill -15 <PID>
The process completes running jobs according to the configured shutdown mode, then exits.
Do not run kill -9 directly. SIGKILL bypasses the JVM shutdown hook and terminates the process immediately, skipping graceful shutdown. If the process does not exit within an acceptable time after kill -15, then use kill -9 as a fallback.
Method 2: Use the Spring Boot actuator shutdown endpoint
For Spring Boot applications, use the built-in actuator to trigger a shutdown event. SchedulerX responds to Spring container shutdown events and completes running jobs before the application exits.
-
Add the actuator dependency to your
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
-
Enable the shutdown endpoint in your application properties:
management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=shutdown
-
Trigger the shutdown:
curl -X GET http://<node-ip>:<port>/actuator/shutdown
Method 3: Use the SchedulerX HTTP endpoint
Enable the built-in SchedulerX HTTP endpoint:
spring.schedulerx2.httpServerEnable=true
spring.schedulerx2.httpServerPort=51886
Trigger the shutdown:
curl -X GET http://<node-ip>:51886/schedulerx/worker/shutdown
Integrate into deployment workflows
Self-managed continuous delivery (CD) pipeline
Include the graceful shutdown logic in the stop script of your CD pipeline. The following example sends SIGTERM, polls for process exit, and falls back to SIGKILL after a timeout:
# After starting the application, write the PID to app.pid.
PID="{Application deployment path}/app.pid"
FORCE=1
if [ -f ${PID} ]; then
TARGET_PID=`cat ${PID}`
kill -15 ${TARGET_PID}
loop=1
while(( $loop<=5 ))
do
# health: Check whether the application process is still running.
# Replace with your own health check command.
health
if [ $? == 0 ]; then
echo "check $loop times, current app has not stop yet."
sleep 5s
let "loop++"
else
FORCE=0
break
fi
done
if [ $FORCE -eq 1 ]; then
echo "App(pid:${TARGET_PID}) stop timeout, forced termination."
kill -9 ${TARGET_PID}
fi
rm -rf ${PID}
echo "App(pid:${TARGET_PID}) stopped successful."
fi
Kubernetes PreStop hook
Use the Kubernetes Pod preStop lifecycle hook to trigger graceful shutdown before a Pod is terminated.
Option A: Exec script
Run a script or send SIGTERM directly:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: my-app-image:latest
lifecycle:
preStop:
exec:
# command: ["/bin/sh", "-c", "kill -15 PID && sleep 30"]
command: ["/bin/sh", "-c", "Script path /stop.sh"]
Option B: HTTP request
Call the appropriate HTTP endpoint based on your application type:
-
Spring Boot applications: Set
pathto/actuator/shutdown. -
Non-Spring applications: Set
pathto/schedulerx/worker/shutdownafter enabling the SchedulerX HTTP endpoint.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: my-app-image:latest
lifecycle:
preStop:
httpGet:
path: /schedulerx/worker/shutdown
port: 51886
scheme: HTTP
Alibaba Cloud platform integration
If you deploy through Enterprise Distributed Application Service (EDAS) or through Microservices Engine (MSE) with Container Service for Kubernetes (ACK), SchedulerX graceful shutdown integrates automatically after you enable graceful shutdown on the platform. For details, see:
Best practices
-
Set a shutdown timeout. Without a timeout, a long-running or stuck job blocks the shutdown indefinitely. Set
graceShutdownTimeoutto a value slightly longer than the expected maximum job duration. -
Avoid
kill -9as the first action. Always sendSIGTERM(kill -15) first and wait for graceful shutdown to complete. UseSIGKILL(kill -9) only as a last resort after the timeout expires. -
Use
WAIT_ALLfor data-sensitive workloads.WAIT_RUNNINGdrops queued jobs, which may cause missed executions. ChooseWAIT_ALLunless queued jobs are safely retriable. -
Verify no active jobs before shutdown. In production, check job execution status before triggering a shutdown to avoid unnecessary wait times or retries.
-
Test graceful shutdown in staging first. Validate that your shutdown configuration, timeout, and integration method work correctly before applying them to production.