Technical article
Service runtime transitions: synchronized start/stop and timeout governance
Starting or stopping a LightESB service is not a flag flip. The runtime API holds the request until the dynamic route loader confirms the Camel context has really started or unloaded — and one response tells you whether you drove that transition, reused one, or arrived too late.
A start request is a transition, not a write
server.running=true is only the request. A service version enters RUNNING only after configuration, required components, exception handling, XML parsing, port binding, and every auto-starting route succeed; any failed required phase is published as STOPPED, without affecting other services or overall application health.
The start/stop API therefore synchronizes on the real outcome: POST /service-management/v1/runtime/start/{id} (or stop/{id}) blocks until the loader confirms the context, and returns the transition verdict inline — no blind polling loops in automation.
One transition, four honest answers
Shared same-direction transitions
Concurrent starts of the same service share one transitionId; later requests join the in-flight transition and return transitionReused=true instead of stacking duplicate work.
Idempotent repeats
A request that already matches the target state returns HTTP 200 with idempotent=true and does not rewrite the configuration — retries are safe.
Opposite direction rejected
A stop arriving while a start is in flight (or vice versa) returns HTTP 409 with RUNTIME_TRANSITION_IN_PROGRESS. No interleaving, no half-states.
Failures carry the real state
Load failure, stop failure, or a timed-out wait returns HTTP 409 RUNTIME_TRANSITION_FAILED with the actual serviceStatus, internalStatus, diagnosticId, a sanitized errorSummary, and timedOut.
The timeout is a wait budget, not a rollback
The API waits 30 seconds by default, tunable globally between 1 and 120 seconds:
lightesb.route.transition-timeout-seconds=30A timeout never rolls back server.running — the background transition may still complete. And when a stop fails while the old context is still alive, the API reports the real RUNNING state plus failure diagnostics, not a comfortable lie.
Real commands, real responses
Start a service and read the verdict straight from the response:
curl -X POST http://localhost:8080/service-management/v1/runtime/start/svc-1
{
"success": true,
"data": {
"serviceStatus": "RUNNING",
"transitionId": "52be2ef9-73a7-4d7d-a4bc-bcb3a5681292",
"transitionReused": false,
"idempotent": false
},
"error": null
}When the wait budget runs out, HTTP 409 says exactly what timed out:
{
"success": false,
"error": {
"code": "RUNTIME_TRANSITION_FAILED",
"message": "等待服务运行状态转换超时",
"details": {
"targetStatus": "RUNNING",
"serviceStatus": "STOPPED",
"timedOut": true
}
}
}After a 409: query, don't counter-attack
The CLI mirrors the API — lightesb service start --id <serviceId> --yes and the matching stop command exit non-zero on HTTP 409 and preserve the server error summary. Automation should query after a failure, never fire a reverse-direction request or blindly overwrite the configuration.
Two read-only endpoints settle the truth: the detail view for public runtime and deployment status, and the route-runtime snapshot for internal status, context state, failure phase, and diagnosticId. If the transition is still in flight, check again later.
GET /service-management/v1/detail/{id}
GET /api/diagnostics/runtime-snapshot?serviceName=DemoSrv&serviceVersion=v1.0.0&component=route-runtime