Skip to content

Handling exceptions when applications do not report errors but time out in stateful transitions - #868

Open
PawelPlesniak wants to merge 102 commits into
developfrom
PawelPlesniak/IncompleteStatefulCommandTransition
Open

Handling exceptions when applications do not report errors but time out in stateful transitions#868
PawelPlesniak wants to merge 102 commits into
developfrom
PawelPlesniak/IncompleteStatefulCommandTransition

Conversation

@PawelPlesniak

@PawelPlesniak PawelPlesniak commented Mar 31, 2026

Copy link
Copy Markdown
Collaborator

Description

Fixes #803
Fixes #869
Fixes #911
Fixes #687

If a segment does not reach the target state, it is marked as in error, and the timeout is logged in the relevant server.
Also defines a set of configurations constructed to fail, and defines a set of unit tests to demonstrate this behaviour.
Error recovery with the supervisor will address what happens if an application completes this outside of the designated window. This is defined in #840

Type of change

  • New feature / enhancement
  • Optimization
  • Bug fix
  • Breaking change
  • Documentation

List of required branches from other repositories

Requires DUNE-DAQ/druncschema#87

Change log

Addressed issues

Now when an application does not complete its transition in the allocated timeout, the session is put into an error state.
Defines a new click command log (implemented in code as def log_on_server to prevent naming conflicts with logging.Loggers defined as log) that allows the user to send a message to the relevant controller or process manager to put into their log file with a selectable severity level.

Other new features

When running in batch mode, the user can start the run with --no-stop-error-batch-mode. Should an error state be encountered, the session is not terminated, and commands can continue to be executed. This is primarily intended for use with integration tests, such that we can inspect the ps and status tables.

Integration tests for failure modes

Defines a set of intentionally failing configurations in config/tests/failure-testing.data.xml, which contain configurations with a set of fake-daq-apps that fail at configurable points in the session lifecycle. These configurations are

  • ft-death-on-boot-nest-app - this kills a nested application (2 segments deep) on boot.
  • ft-death-on-boot-top-app - this kills the top application on boot.
  • ft-death-post-boot-nest-app - this kills a nested application (2 segments deep) after boot, before applications are marked as ready.
  • ft-death-post-boot-top-app - this kills the top application after boot, before applications are marked as ready.
  • ft-fsm-cmd-timeout-nest-app - this times out an FSM transition on a nested application.
  • ft-fsm-cmd-timeout-top-app - this times out an FSM transition on the top application.
  • ft-fsm-cmd-death-nest-app - this kills a nested fake daq app during a FSM transition.
  • ft-fsm-cmd-death-top-app - this kills the top fake daq app during a FSM transition.

The differences between the on-boot and post-boot are useful to see, as the post-boot configs allow the applications that die to register themselves on the connectivity service before dying, hence there is different behaviour.

The differences between the nest-app and top-app allow the user to visualize the effect of a nested hierarchy on the control tree, and how the releveant children applications register themselves to the segment parents. The user shoudl expect to see the majority of the apps in the status table on boot when using a nest config, and only the top two apps when using the top config.

Note that these configurations use the FSMconfiguration_noAction state machine, and will not behave fulliy in the standard way. An example includes not being able to reach the running state as there is no run number allocated, which will be reported as a generic gRPC error.

These tests have been integrated into the unit test framework, which can be executed as (from the local drunc root)

source scripts/setup_drunc_config_path.sh
pytest src/drunc/integtest/<integ_test_file_name>

It is recommended for the tester to use --integtest-verbosity 5 to see what is happening during the process, and if more details are wanted from the pytest side, the user can run the tests as pytest -s to show what would be printed.

Suggested manual testing checklist

Run each of the integration tests as defined above.

Developer checklist

Prior to marking this as "Ready for Review"

Tests ran on: np04-srv-029 from release NFD_DEV_260709_A9.

Unit tests - some tests can't be ran on the CI. This is documented. If this PR checks a feature that can't be tested with CI, this has been marked appropriately.

Integration tests - the daqsystemtest_integtest_bundle requires a lot of resources, and connections to the EHN1 infrastructure. Check the cross referenced list if you can't run these. The developer needs to run at least the .

  • Unit tests (pytest --marker) passed
    • With relevant marker
    • Without marker
  • Integration tests passed
    • Only daqsystemtest_integtest_bundle.sh -k minimal_system_quick_test.py
    • Full daqsystemtest_integtest_bundle.sh
  • Testing skipped as there are no core code changes in this PR, this only relates to documentation/CI workflows

Final checklist prior to marking this as "Ready for Review"

  • Code is clearly commented.
  • New unit tests have been added, or is documented in # ISSUE NUMBER
  • A suitable reviewer has been chosen from this list.

Reviewer checklist

  • This branch has been rebased with develop prior to testing.
  • Suggested manual tests show changes.
  • CI workflows fails documented (if present)
  • Integration tests passed
    • Only concern yourself if failures related to drunc are in the log files
    • If non-drunc failure appears:
      • Validate failure in fresh working area
      • Contact Pawel if unsure

Once the features are validated and both the unit and integration tests pass, the PRs is ready to be merged.

Prior to merging

Choose one of the following an complete all substeps
  • Changes only affect the Run Control, are in a single repository, and do not affect the end user.
    • Changes are documented in docstrings and code comments
    • Wiki has been updated if architectural or endpoint changes
  • Otherwise
    • Workflow changes demonstrated in the Change Log (if necessary)
    • Wiki has been updated (if necessary)
    • #daq-sw-librarians Slack channel notified (see below)

Once completed, the reviewer can merge the PR.

Notification message for a Slack channel

Note - this should be to #dunedaq-integration for general workflow that isn't during a release candidate period, and to #daq-release-prep otherwise.

For an single merge that changes the user workflow

The CCM WG has an isolated PR ready to merge that affects user workflows. The PR is:

_URL_

I will leave time for any comments, otherwise will merge these at the end of the work day _Insert your time zone_.

For co-ordinated merge

The CCM WG has a set of co-ordinated merges ready to merge. The PRs are:

_URL_

_URL_


I will leave time for any comments, otherwise will merge these at the end of the day.

@PawelPlesniak

Copy link
Copy Markdown
Collaborator Author
image In the case where a second application also fails to complete a transition in time, the same error gets thrown. This is likely caused by the nested structure, and the fact that there are multiple layers to this configuration. A robust solution to this problem will take longer to achieve, but I will continue working on it.

@PawelPlesniak PawelPlesniak changed the title Generating an environment for which the issue can be recreated Handling exceptions when applications do not report errors but time out in stateful transitions Mar 31, 2026
@PawelPlesniak
PawelPlesniak changed the base branch from prep-release/fddaq-v5.6.0 to develop June 4, 2026 16:05
@PawelPlesniak

PawelPlesniak commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author
  • Log files do not contain wierd characters from redirecting rich ASCII output to a file with colors
  • Top app config failure not working?

@PawelPlesniak

PawelPlesniak commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author
  • Stream handler has no logging time zone, file name, line number, etc?
  • Duplicate logs of apps failing
  • Remove old logs used for debugging
  • Add druncschema dependency to this PR log
  • Integrate the failure mode testing into the unit tests

@PawelPlesniak

Copy link
Copy Markdown
Collaborator Author

I will rerun the integration tests tomorrow in both drunc and daqsystemtest, lets get this PR merged and put away

@PawelPlesniak

Copy link
Copy Markdown
Collaborator Author

All new drunc integration tests have passed

pytest -s src/drunc/integtest/failure_mode_* --integtest-verbosity 5
...
============ 49 passed in 653.81s (0:10:53) ===============

All previous drunc integration tests have also passed.

@PawelPlesniak

Copy link
Copy Markdown
Collaborator Author

Unit tests now pass

234 passed, 8 skipped, 1 xfailed, 108 warnings in 79.11s (0:01:19)

Integration tests passed on np04-srv-028 with NFD_DEV_260803_A9

+++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++ SUMMARY ++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++

Tue Aug  4 12:09:41 PM CEST 2026
Log file is: /tmp/pytest-of-pplesnia/dunedaq_integtest_bundle_20260804112614.log

⮕ Running daqsystemtest/3ru_1df_multirun_test.py ⬅
======================== 6 passed ✅ in 251.70s (0:04:11) =========================
⮕ Running daqsystemtest/3ru_3df_multirun_test.py ⬅
======================== 6 passed ✅ in 249.92s (0:04:09) =========================
⮕ Running daqsystemtest/disabled_tpg_test.py ⬅
========================= 3 passed ✅ in 61.04s (0:01:01) =========================
⮕ Running daqsystemtest/example_system_test.py ⬅
======================== 12 passed ✅ in 244.42s (0:04:04) ========================
⮕ Running daqsystemtest/fake_data_producer_test.py ⬅
======================== 6 passed ✅ in 237.60s (0:03:57) =========================
⮕ Running daqsystemtest/long_window_readout_test.py ⬅
============================== 1 skipped 🟡 in 1.39s ==============================
⮕ Running daqsystemtest/minimal_system_quick_test.py ⬅
============================== 4 passed ✅ in 54.03s ==============================
⮕ Running daqsystemtest/readout_type_scan_test.py ⬅
======================== 33 passed ✅ in 609.40s (0:10:09) ========================
⮕ Running daqsystemtest/sample_ehn1_multihost_test.py ⬅
======================== 4 skipped 🟡 in 126.48s (0:02:06) ========================
⮕ Running daqsystemtest/small_footprint_quick_test.py ⬅
============================== 3 passed ✅ in 55.55s ==============================
⮕ Running daqsystemtest/tpg_state_collection_test.py ⬅
======================== 5 passed ✅ in 108.56s (0:01:48) =========================
⮕ Running daqsystemtest/tpreplay_test.py ⬅
======================== 6 passed ✅ in 167.04s (0:02:47) =========================
⮕ Running daqsystemtest/tpstream_writing_test.py ⬅
======================== 4 passed ✅ in 108.24s (0:01:48) =========================
⮕ Running daqsystemtest/trigger_bitwords_test.py ⬅
======================== 18 passed ✅ in 312.92s (0:05:12) ========================

@PawelPlesniak

PawelPlesniak commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

@emmuhamm please review the unresolved comment replies, the rest has been addressed

Comment on lines +1627 to +1632
# Children nodes (ignore exclusion).
child_list = self.address_target_path(
request.target,
request.execute_on_all_subsequent_children_in_path,
include_excluded_nodes=False,
)

@jamesturner246 jamesturner246 Aug 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just saw this flash past my screen. NB with include_excluded_nodes=False, you're actually not including excluded nodes, contrary to the comment.

ED: I realise now my (ignore exclusion) comment is kind of ambiguous. Just checking intent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks James! Either way, we want to include excluded nodes, as the log_on_server command is not stateful

@emmuhamm emmuhamm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing my comments, these look great to me! Theres a thread that I've pinged you on since you explicitly asked to leave that unresolved, and another minor comment about updating the code comments, but none of them should block this going in.

Theres also this request you mentioned:

Note to self - requested from MRiganSUSX , list the application that did not complete in time, and tell the user to look at the logs of that specific one

Has this been done? (I haven't dug in the code yet, and might be easier to ask you to confirm >.<)

Aside from that, the only thing I'll ask for is:

  • a minor conflict that needs to be resolved
  • pytest (done!)
  • drunc integtest (done!)
  • full daqsystemtest (done!)

so after the conflict I'd be happy with evidence that both the pytest, local drunc integtest, and msqt passes and we can get this in!

Comment thread src/drunc/controller/interface/commands.py Outdated
Comment on lines 294 to 304
_PS_COLUMNS = ["session", "friendly_name", "user", "host", "uuid", "alive", "exit_code"]
_STATUS_COLUMNS = [
"name",
"info",
"state",
"substate",
"in_error",
"included",
"endpoint",
]
_EXEC_REPORT_COLUMNS = ["name", "command_execution", "fsm_transition"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah thats fair. The comment was mainly focused on how I'm not a fan of my own design choices, primarily having to hardcode status columns in actual tests.

Eg. we shouldn't ever do table['state'] when writing the tests themselves, since this is prone to error (eg if the name 'state' changes in the future or whatever).

Personally it would be better if when we grab the table we can do a table.state when writing the tests, and abstract away the implementation to the testing utils.

Now obviously this is something far beyond the scope of this PR, but this is something to think about.

Comment thread pyproject.toml Outdated
Comment on lines +30 to +33
pytestmark = pytest.mark.skipif(
drunc_missing,
reason="drunc is not present in DUNEDAQ_DB_PATH, skipping drunc integration tests",
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PawelPlesniak pinging you on this again since you explicitly asked to leave this unresolved. Is this thread fine now?

# successful and we can return, otherwise, we will log the error and place the
# session in an error state if required.
in_error_state = obj.get_driver("controller").status().status.in_error
if not in_error_state and not put_in_error_state:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the comments! A slight request on the comments:

# Determine whether the session should be placed into an error state. See usage for examples on why such a session _should_ be placed into the error state.

Its a lot of handholding but I think this is important, at least it'll tell a developer what the variables does and tells them to read the code for a few examples of why put_in_error_state needs to be used.

@PawelPlesniak

Copy link
Copy Markdown
Collaborator Author

Theres a thread that I've pinged you

Thanks

Has this been done? (I haven't dug in the code yet, and might be easier to ask you to confirm >.<)

Yep

a minor conflict that needs to be resolved

Also done ;)

Other comments will be addressed in the relevant threads now

Thanks!

@PawelPlesniak

Copy link
Copy Markdown
Collaborator Author

At this stage, I think we're coming to a close, the last topic is the discussion on the in_error_state flag

@emmuhamm emmuhamm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this stage, I think we're coming to a close, the last topic is the discussion on the in_error_state flag

Agree! Thats why I'm going to approve this right now so you can merge it whenever this is resolved but so it isn't blocked on my availability.

In any case I've seen all the code already and whatever's gonna change is just a comment. So as long as the aformentioned checks are done this can go in.

Thanks for this nice work my guy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

5 participants