By nghxni

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=30

A 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
Runtime start/stop APIRoute loading boundaries