ProcessInfoNode does not set up alive supervision for State_Manager components

Open Beginner friendly
#957 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
cpp
Domain
backend, testing

Research direction

Read process_info_node.cpp, especially the constructor near line 75 and the existing isSupervised() method near line 266. Change the supervision setup to cover StateManager and add a unit test for supervision construction and LCM_ALIVE_INTERFACE_PATH injection. Done when the test confirms a State_Manager component receives both.

Written by the indexing model from the issue text.

Description

Description

Components configured with application_type: "State_Manager" are never alive-supervised by the Launch Manager, and they cannot send alive notifications.

ProcessInfoNode's constructor sets up alive supervision and injects LCM_ALIVE_INTERFACE_PATH only for ReportingAndSupervised:

https://github.com/eclipse-score/lifecycle/blob/c7502b563/score/launch_manager/src/daemon/src/process_group_manager/details/process_info_node.cpp#L75

if (app_profile.application_type == configuration::ApplicationType::ReportingAndSupervised)
{
    ...
    supervision_handle_ = process_handling_.supervision_factory.constructSupervision(...);
    ...
    config_.deployment_config.environmental_variables.add(
        "LCM_ALIVE_INTERFACE_PATH", supervision_handle_->getConnectionId());
}

But isSupervised() in the same class treats StateManager as supervised too:

https://github.com/eclipse-score/lifecycle/blob/c7502b563/score/launch_manager/src/daemon/src/process_group_manager/details/process_info_node.cpp#L266-L271

bool ProcessInfoNode::isSupervised() const
{
    const auto app_type = config_.component_properties.application_profile.application_type;
    return app_type == configuration::ApplicationType::ReportingAndSupervised ||
           app_type == configuration::ApplicationType::StateManager;
}

Impact
- A State_Manager process gets no LCM_ALIVE_INTERFACE_PATH, so constructing score::mw::lifecycle::Alive throws std::runtime_error("Failed to get interface path") (AliveImpl::connectToPhmDaemon()).
- No supervision worker is created for the State_Manager component, so a hung or stalled State Manager is never detected, and no recovery action is triggered.
- This contradicts the documented behavior of State_Manager: "uses lifecycle APIs, sends alive notifications, and has permission to change the active Run Target" (configuration.rst, launch_manager.schema.json).

### Problem notifications

Notification needed: no external notification is needed. This is a functional defect in alive supervision, not a vulnerability.
It is safety-relevant (a supervised component is not supervised), so the maintainers of the alive supervision / Component refactoring are informed via this issue.
cc @NicolasFussberger @WilliamRoebuck (reviewer / author of the related changes in #779 / #522)

### Analysis results

**Design intent: State_Manager is meant to be supervised**
- `configuration.rst` / `launch_manager.schema.json`: State_Manager "sends alive notifications".
- `scripts/config_mapping/lifecycle_config.py` `is_supervised()` keeps `alive_supervision` for `State_Manager`.
- `ProcessInfoNode::isSupervised()` and `component.cpp` `isSupervised()` both include `StateManager`.
- Review comment in #779 (https://github.com/eclipse-score/lifecycle/pull/779#discussion_r4375950483):
  > The StateManager application type was also meant to be supervised. We don't really use it now, but would be good to add this already.
- AoU draft in #863: `aou_req__health_monitor__lm_alive_cfg` requires processes using the Health Monitor to be configured as `Reporting_And_Supervised` **or `State_Manager`**.

**Regression history**
| PR | Change |
|---|---|
| #248 | `ConfigurationAdapter::appendAliveInterfaceEnvironment()` injected `LCM_ALIVE_INTERFACE_PATH` for both `ReportingAndSupervised` and `StateManager` (correct). |
| #455 | Config adapter removed. Env injection moved to the `ProcessInfoNode` constructor with a `ReportingAndSupervised`-only condition. The PHM daemon still created a worker for State_Manager, so the worker expected alive notifications that the process could never send (supervision expires if `min_indications > 0`). |
| #522 | Supervision construction moved into the same `ReportingAndSupervised`-only block, so State_Manager now has no supervision at all. The same PR added `isSupervised()` including `StateManager`, but did not use it for this condition. |
| #779 | The new `Component` class was fixed after review (`component.cpp` `isSupervised()` includes `StateManager`), but `ProcessInfoNode` was not. `Graph` still uses `std::variant<ProcessInfoNode, RunTarget>`, so the `Component` fix is not on the production path. |

No unit or integration test checks env injection or supervision construction for State_Manager, so the regression was not detected.

### Solution

Use the existing `isSupervised()` in the `ProcessInfoNode` constructor:

```diff
-    if (app_profile.application_type == configuration::ApplicationType::ReportingAndSupervised)
+    if (isSupervised())
     {

and add a unit test asserting that a State_Manager component gets alive supervision and LCM_ALIVE_INTERFACE_PATH.

(Alternatively, this is resolved once Graph switches from ProcessInfoNode to the new Component class, which already handles StateManager correctly. Until then, the production path needs the fix above.)

### Error Occurrence Rate
**Reproducible**

### How to reproduce
```markdown
1. Configure a component with:
   ```json
   "application_profile": {
       "application_type": "State_Manager",
       "alive_supervision": { "reporting_cycle": 0.5, "failed_cycles_tolerance": 2, "min_indications": 1, "max_indications": 3 }
   }
2. In that application, construct score::mw::lifecycle::Alive and call ReportAlive() periodically.
3. Start the Launch Manager.

Expected: the process receives LCM_ALIVE_INTERFACE_PATH, connects to the alive monitor, and is supervised (stopping it, e.g. kill -STOP, leads to a supervision failure and a recovery action).

Actual (main): LCM_ALIVE_INTERFACE_PATH is not set, Alive construction throws "Failed to get interface path", and no supervision is created, so stopping the process is never detected.
(lifecycle v0.4.0 – v0.6.x: env is not set but a worker is created, so supervision expires and a recovery action runs even when the process is healthy.)

### Error Occurrence  Rate

Reproducible

### How to reproduce

**Steps**
1. Configure a component with application type `State_Manager` and alive supervision, e.g.:
   ```json
   "application_profile": {
       "application_type": "State_Manager",
       "alive_supervision": {
           "reporting_cycle": 0.5,
           "failed_cycles_tolerance": 2,
           "min_indications": 1,
           "max_indications": 3
       }
   }
2. In that application, construct score::mw::lifecycle::Alive and call ReportAlive() periodically.
3. Start the Launch Manager so that the component is launched.

Expected
- The process receives LCM_ALIVE_INTERFACE_PATH and connects to the alive monitor.
- The component is alive-supervised: stopping the process (e.g. kill -STOP <pid>) leads to a supervision failure and the configured recovery action.

Actual (main)
- LCM_ALIVE_INTERFACE_PATH is not set for the process.
- Constructing Alive throws std::runtime_error("Failed to get interface path").
- No supervision is created for the component, so stopping the process is never detected.

Actual (lifecycle v0.4.0 – v0.6.x)
- LCM_ALIVE_INTERFACE_PATH is not set, but the alive monitor still creates a supervision worker for the component.
- Because the process can never report alive, supervision expires and the recovery action runs even when the process is healthy (with min_indications > 0).


### Supporting Information

**Operational state**
- Launch Manager startup, while the State_Manager component is launched as part of the initial Run Target.
- The defect is in `ProcessInfoNode` construction (`Graph` setup), so it applies to every launch of a State_Manager component, not just a specific runtime condition.

**Environment**
- Observed on lifecycle v0.6.1 (Yocto, qemuarm64).
- Confirmed by code inspection on main (c7502b563).
- First lifecycle tag containing #455: v0.4.0. First tag containing #522: v0.7.0.

**Observations**
- State_Manager application: `Alive` construction fails with `std::runtime_error("Failed to get interface path")` (`AliveImpl::connectToPhmDaemon()`), because `LCM_ALIVE_INTERFACE_PATH` is not set.
- lifecycle v0.4.0 – v0.6.x: alive supervision of the State_Manager component expires and the recovery action (Run Target switch) is triggered although the process is running normally.
- main: no "Setting up alive supervision for <component>" debug log for the State_Manager component, i.e. no supervision is created.

**Relevant code (main, c7502b563)**
- `process_info_node.cpp#L75`: supervision construction and `LCM_ALIVE_INTERFACE_PATH` injection, `ReportingAndSupervised` only
- `process_info_node.cpp#L266-L271`: `isSupervised()` includes `StateManager`
- `component.cpp#L25-L63`: new `Component` class handles `StateManager` correctly (not used by `Graph` yet)
- `alive/src/details/AliveImpl.cpp`: `readInterfacePath()` / `connectToPhmDaemon()`

**Current workaround**
- The State Manager does not use `Alive`, and `min_indications: 0` is set for its component to avoid supervision expiry.
- With this workaround, a stalled State Manager is not detected.

**Related**
- #606 Escalate ProcessInfoNode construction failures
- #918 PGM can silently miss supervision failures notifications
- #779 review comment: https://github.com/eclipse-score/lifecycle/pull/779#discussion_r4375950483

### Classification

Critical

### First Affected Release

pre-0.5

### Last Affected Release

not released (main)

### Expected Fixed Release

1.0

### Category

- [x] Safety Relevant
- [ ] Security Relevant
Dominant language
C++
Stars
7
Forks
37
Avg merge
2d 9h
Merged PRs (30d)
119

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

  • No Dockerfile or Docker Compose file
  • Has a pull request template
  • No contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from eclipse-score/lifecycle

All issues in eclipse-score/lifecycle

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.