Skip to content

Revert shell exec behaviour change#638

Closed
laDok8 wants to merge 1 commit intoxtf-cz:0.xfrom
laDok8:0.x
Closed

Revert shell exec behaviour change#638
laDok8 wants to merge 1 commit intoxtf-cz:0.xfrom
laDok8:0.x

Conversation

@laDok8
Copy link
Contributor

@laDok8 laDok8 commented Feb 9, 2026

Backport for #637

Summary by Sourcery

Restore previous pod shell execution retry semantics to avoid failing fast on pod startup and preserve the last successful command result.

Bug Fixes:

  • Ensure executeWithRetry returns the last successful shell execution result when no output is produced instead of always failing after all retries.
  • Prevent the shell execution callback from prematurely marking execution as done on transient pod startup failures.

Enhancements:

  • Adjust retry success criteria to treat the presence of either stdout or stderr as a successful execution attempt.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 9, 2026

Reviewer's Guide

This PR adjusts PodShell’s executeWithRetry and WebSocket failure handling to restore previous shell execution behavior: it now retries until any stdout/stderr is produced, returns the last successful result instead of throwing after retries, and ignores onFailure events during pod startup to avoid fail-fast behavior.

Sequence diagram for updated executeWithRetry shell execution behavior

sequenceDiagram
    actor Caller
    participant PodShell
    participant PodShellOutput

    Caller->>PodShell: executeWithRetry(retryCount, retryDelay, commands)
    loop attempts 1..retryCount
        PodShell->>PodShell: execute(commands)
        alt execute succeeds
            PodShell-->>PodShellOutput: PodShellOutput pso
            PodShell->>PodShell: lastSuccessfulResult = pso
            alt stdout or stderr present
                PodShell-->>Caller: return pso
                note over Caller,PodShell: break
            else no stdout and no stderr
                alt attempt < retryCount
                    PodShell->>PodShell: Thread.sleep(retryDelay)
                else attempt == retryCount
                    PodShell-->>Caller: return lastSuccessfulResult
                    note over Caller,PodShell: break
                end
            end
        else execute throws WaiterException
            PodShell-->>PodShell: catch WaiterException e
            alt attempt >= retryCount
                PodShell-->>Caller: throw WaiterException
                note over Caller,PodShell: break
            else attempt < retryCount
                PodShell->>PodShell: Thread.sleep(retryDelay)
            end
        end
    end
Loading

Updated class diagram for PodShell retry and failure handling

classDiagram
    class PodShell {
        - String podName
        + PodShellOutput execute(String commands)
        + PodShellOutput executeWithRetry(int retryCount, int retryDelay, String commands)
    }

    class PodShellOutput {
        + String getOutput()
        + String getError()
        + List getOutputAsList()
    }

    class WaiterException {
    }

    class PodExecWebSocketListener {
        + void onOpen()
        + void onFailure(Throwable throwable, Response response)
    }

    PodShell --> PodShellOutput : uses
    PodShell --> WaiterException : throws
    PodExecWebSocketListener --> PodShell : notifies
Loading

File-Level Changes

Change Details Files
Restore executeWithRetry semantics to return last successful result once any stdout/stderr is seen and avoid failing fast on transient WebSocket failures.
  • Track the last successful PodShellOutput during retries and return it after all attempts instead of unconditionally throwing a WaiterException
  • Change the success condition to return as soon as either stdout or stderr is non-empty rather than checking only the output list
  • Move the retry sleep block out of the exception handler so it also runs after empty results, and rethrow the last WaiterException immediately on the final attempt
  • Modify the WebSocket onFailure callback to no-op instead of logging an error and marking execution as done, preventing early termination on pod startup failures
core/src/main/java/cz/xtf/core/openshift/PodShell.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In executeWithRetry, consider defensively handling the case where lastSuccessfulResult is still null before returning (e.g., throw a clear exception) so the method remains robust against future changes that might alter the retry loop behavior.
  • In onFailure, completely suppressing both executionDone.set(true) and logging may make failures hard to diagnose; consider at least a low-level (debug/trace) log or a comment explicitly stating under what conditions it is safe to ignore failures here.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `executeWithRetry`, consider defensively handling the case where `lastSuccessfulResult` is still null before returning (e.g., throw a clear exception) so the method remains robust against future changes that might alter the retry loop behavior.
- In `onFailure`, completely suppressing both `executionDone.set(true)` and logging may make failures hard to diagnose; consider at least a low-level (debug/trace) log or a comment explicitly stating under what conditions it is safe to ignore failures here.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@laDok8
Copy link
Contributor Author

laDok8 commented Feb 10, 2026

I'm currently unable to replicate this problem on 0.x branch. It's possible the error is only on main branch due to openshift-client upgrade. Closing

@laDok8 laDok8 closed this Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant