DC-044: fix WorkflowEngine healthCheckService — servicesStateManager.getState bug
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled

The bundled-workflows.js:310 call site used a non-existent .getState()
method AND forgot to await. The Promise short-circuited via '|| []' to an
empty array, so every health-check-on-interval workflow ran every 5 min
reporting 'Action health-check failed: servicesStateManager.getState is
not a function' while silently iterating over zero services. Visible on
both DNS2 (production) and dc-contabo-de (test server) — same code, same
bug, same log spam.

Fix: 'await servicesStateManager.read().catch(() => []) || []' — uses the
actual async method, returns empty array on read() failure (corrupt or
missing state file shouldn't break the workflow), preserves the original
short-circuit guard.

New regression test __tests__/bundled-workflows-health-check.test.js with
5 cases:
1. uses .read() not the non-existent .getState() — does not throw
2. returns checked/healthy counts from read() output
3. gracefully degrades if read() throws — empty services list, no crash
4. servicesStateManager absent on ctx → no crash, empty result
5. single service (non-template serviceId) path still works

Tests: 1219/1219 pass (1214 baseline + 5 new). ESLint: clean for the new
file. Test fixture note: had to clearInterval the constructor's
scheduledJobs so Jest could exit cleanly — scheduled workflows are not
under test here.
This commit is contained in:
Hermes
2026-07-13 15:38:11 -07:00
parent 49e6c9cc11
commit b492e1cd4f
3 changed files with 142 additions and 2 deletions
@@ -307,7 +307,11 @@ class WorkflowEngine extends EventEmitter {
const results = [];
const servicesStateManager = this.ctx.servicesStateManager;
if (servicesStateManager) {
const services = servicesStateManager.getState() || [];
// StateManager exposes async read() — never getState(). The previous
// call site used the wrong method name AND forgot to await, returning
// a Promise instead of an array; the `|| []` short-circuit then made
// every check silently no-op with "Health check failed" errors.
const services = await servicesStateManager.read().catch(() => []) || [];
for (const service of services) {
if (service.containerId) {
try {