Skip to content

fix: avoid reading external plugin stdout to memory#4234

Merged
Bravo555 merged 3 commits into
thin-edge:mainfrom
Bravo555:improve/config-plugin-get-stream
Jul 2, 2026
Merged

fix: avoid reading external plugin stdout to memory#4234
Bravo555 merged 3 commits into
thin-edge:mainfrom
Bravo555:improve/config-plugin-get-stream

Conversation

@Bravo555

@Bravo555 Bravo555 commented Jun 30, 2026

Copy link
Copy Markdown
Member

Proposed changes

Similar to 5fda661, stream result of external config plugin instead of loading everything to memory. Not as impactful as log plugin, because usually people won't be having config files bigger than available RAM, but nevertheless behaviour was changed to keep consistency between the two plugins.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Improvement (general improvements like code refactoring that doesn't explicitly fix a bug or add any new functionality)
  • Documentation Update (if none of the other choices apply)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Paste Link to the issue

#4222 (review)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA (in all commits with git commit -s. You can activate automatic signing by running just prepare-dev once)
  • I ran just format as mentioned in CODING_GUIDELINES
  • I used just check as mentioned in CODING_GUIDELINES
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

@Bravo555 Bravo555 added the theme:configuration Theme: Configuration management label Jun 30, 2026
@Bravo555 Bravo555 temporarily deployed to Test Pull Request June 30, 2026 18:14 — with GitHub Actions Inactive
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 42.04545% with 51 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ates/extensions/tedge_config_manager/src/plugin.rs 38.18% 25 Missing and 9 partials ⚠️
.../core/tedge_api/src/workflow/log/logged_command.rs 63.63% 1 Missing and 7 partials ⚠️
...tes/core/tedge_api/src/workflow/log/command_log.rs 33.33% 4 Missing ⚠️
.../core/tedge_agent/src/operation_workflows/actor.rs 0.00% 3 Missing ⚠️
crates/extensions/tedge_log_manager/src/plugin.rs 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Robot Results

✅ Passed ❌ Failed ⏭️ Skipped Total Pass % ⏱️ Duration
949 0 7 949 100 2h56m27.408601s

@albinsuresh albinsuresh left a comment

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.

LGTM. Just a few minor remarks/queries.

tempfile::NamedTempFile::new_in(self.tmp_dir.as_std_path()).map_err(|err| {
self.plugin_error(format!(
"Failed to create temporary file in {}: {err}",
tempfile::env::temp_dir().to_string_lossy()

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.

Suggested change
tempfile::env::temp_dir().to_string_lossy()
self.tmp_dir.as_str()

I see that it was inherited from crates/extensions/tedge_log_manager/src/plugin.rs in 5fda661.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed in b4c1681

Comment on lines +154 to +156
let child = command.spawn().map_err(|err| self.plugin_error(err))?;
let output = child
.wait_with_output(command_log)

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.

Wondering why you took this "spawn child wait for output" approach here as opposed to the command.status() approach taken in crates/extensions/tedge_log_manager/src/plugin.rs. The command.status() approach felt more straightforward, especially about the intent of not caring about the stdout or stderr. I understand that the output.stdout/stderr would be None in this case as well, as they are redirected to the files. But, its' not as direct as the other.

Since you only wrote the simpler status based version for the log_manager/plugin.rs, there must have been a specific reason why you took a different approach here. Just trying to understand what that is.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Okay, the problem is that log plugin's get operation isn't logged, but config plugin's get operation is logged.
To verify that config plugin's get operation keeps being logged, I added a check to the config plugin's test in 782d86b.
The spawn + wait_with_output method here was chosen to pass the command_log to log stdout to the operation log, however this just doesn't work because stdout is routed to file, not pipe.
So to avoid reading all of stdout to memory and also log stdout to the operation log, we'll have to do something like this:

  1. create tempfile for stdout
  2. route process stdout to tempfile
  3. call .status() to wait for process to exit
  4. open both stdout and stderr tempfiles and copy their contents to operation logfile
  5. persist operation logfile
  6. then open and read stdout file again for upload

We write the file, then read it twice, keeping all its contents in a logfile, but we don't load all stdout into memory, so it's okay. I will implement these changes.

@Bravo555 Bravo555 requested a deployment to Test Pull Request July 1, 2026 13:00 — with GitHub Actions Waiting
@Bravo555 Bravo555 temporarily deployed to Test Pull Request July 1, 2026 17:55 — with GitHub Actions Inactive
@Bravo555 Bravo555 force-pushed the improve/config-plugin-get-stream branch from d28787a to 8053ad6 Compare July 2, 2026 08:38
@Bravo555 Bravo555 temporarily deployed to Test Pull Request July 2, 2026 08:38 — with GitHub Actions Inactive

@rina23q rina23q 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.

LGTM

@albinsuresh albinsuresh left a comment

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.

Approving again with some minor suggestions.

}

/// A command output that allows reading from it, no matter if output was captured to memory or attached to a file.
pub struct CommandOutput<'a> {

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.

That's a nice abstraction.

logger.write_all(b"EOF\n").await?;
let mut stdout = output.stdout;
if !stdout.fill_buf().await?.is_empty() {
logger.write_all(b"stderr <<EOF\n").await?;

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.

Suggested change
logger.write_all(b"stderr <<EOF\n").await?;
logger.write_all(b"stdout <<EOF\n").await?;

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.

I think both this and below comments are referring to old commits. These don't exist now and also when I reviewed it.

logger.write_all(b"EOF\n\n").await?;
} else {
logger.write_all(b"stdout (EMPTY)\n").await?;
logger.write_all(b"stderr (EMPTY)\n\n").await?;

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.

Suggested change
logger.write_all(b"stderr (EMPTY)\n\n").await?;
logger.write_all(b"stdout (EMPTY)\n\n").await?;

Bravo555 added 3 commits July 2, 2026 12:55
Signed-off-by: Marcel Guzik <marcel.guzik@cumulocity.com>
Signed-off-by: Marcel Guzik <marcel.guzik@cumulocity.com>
Similar to 5fda661, stream result of external config plugin instead of
loading everything to memory. Not as impactful as log plugin, because
usually people won't be having config files bigger than available RAM,
but nevertheless behaviour was changed to keep consistency between the
two plugins.

Signed-off-by: Marcel Guzik <marcel.guzik@cumulocity.com>
@Bravo555 Bravo555 force-pushed the improve/config-plugin-get-stream branch from 8053ad6 to adba130 Compare July 2, 2026 12:55
@Bravo555 Bravo555 temporarily deployed to Test Pull Request July 2, 2026 12:55 — with GitHub Actions Inactive
@Bravo555 Bravo555 added this pull request to the merge queue Jul 2, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 2, 2026
@Bravo555 Bravo555 added this pull request to the merge queue Jul 2, 2026
Merged via the queue into thin-edge:main with commit 28a6fdf Jul 2, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

theme:configuration Theme: Configuration management

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants