Skip to content

feat(execbroker): propagate middleware errors - #167

Merged
luoliwoshang merged 1 commit into
xgo-dev:mainfrom
MeteorsLiu:feat/execbroker-middleware-error
Aug 13, 2026
Merged

feat(execbroker): propagate middleware errors#167
luoliwoshang merged 1 commit into
xgo-dev:mainfrom
MeteorsLiu:feat/execbroker-middleware-error

Conversation

@MeteorsLiu

Copy link
Copy Markdown
Collaborator

No description provided.

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot 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.

Review summary

The middleware signature migration to func(Request) (Request, error) is clean and applied consistently across Command, CommandContext, and Run. All call sites are updated and the module compiles. TestMiddlewareErrorStopsCommand is a strong test — it covers all three entry points and asserts both error propagation (errors.Is) and that no output is produced, directly verifying non-execution. Lock release on the middleware error path is correct, and there is no path where a rejected command can still execute (cmd.Err is honored by Start(), and Run returns before mutating/launching the caller's cmd).

A few non-blocking items are noted inline. Additionally, the doc comments on Command/CommandContext (execbroker.go:80-81, :91) and Run (:102-103) still describe only the pass-through behavior and don't mention that a middleware rejection is now surfaced via cmd.Err (fails at Start()) or returned directly by Run before execution — worth a sentence each so the non-obvious error path is discoverable.

if err != nil {
cmd.Err = err
}
apply(cmd, req)

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.

On the error path, Command/CommandContext still build the cmd from the middleware-mutated req.Name (running a LookPath) and then run apply(), copying the mutated env/dir/streams onto a command that was rejected. This is functionally safe because cmd.Err short-circuits Start()/Run(), but it's asymmetric with Run (which returns early at line 121 without mutating the caller's cmd) and exposes rejected-command mutations to any caller that inspects cmd before running it. Consider short-circuiting on error to keep the three paths symmetric, e.g.

if err != nil {
    cmd := exec.Command(name, args...)
    cmd.Err = err
    return cmd
}

if scope.Middleware != nil {
req = scope.Middleware(req)
var err error
req, err = scope.Middleware(req)

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.

The user-supplied middleware now runs while scopeMu.RLock() is held (acquired at line 135, released at 159/164). Since this change lets middleware run arbitrary logic (and return errors), the re-entrancy risk is worth flagging: if a middleware calls back into Do (which takes scopeMu.Lock()) on the same goroutine it will deadlock, and holding the shared read lock for the full duration of arbitrary user code lengthens lock-hold time on the hot Command/CommandContext/Run path. Consider snapshotting the needed Scope fields (including the Middleware value) under the lock, RUnlock, then invoking middleware outside the critical section.

@luoliwoshang luoliwoshang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@luoliwoshang
luoliwoshang merged commit b416475 into xgo-dev:main Aug 13, 2026
8 checks passed
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.

2 participants