Skip to content

feat: retry only an unmet condition with retry.on: until - #14

Merged
piekstra merged 3 commits into
mainfrom
piekstra/retry-poll-only
Oct 26, 2026
Merged

piekstra merged 3 commits into
mainfrom
piekstra/retry-poll-only

Conversation

@piekstra

@piekstra piekstra commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Summary

A step with retry and until retries two kinds of attempt: one that failed (non-zero exit, unmet expect) and one that succeeded with until still false. For a poll against a system that must not see a repeated request after an error, the first kind is unsafe: a transient error turns into a second call.

retry.on: until opts a step into retrying only the second kind. The first failed attempt ends the step, with that attempt's own headline (its stderr or exit code), and no further attempts.

retry: { attempts: 12, delay: 10s, until: self.outputs.status == 'posted', on: until }
  • on defaults to any, so existing flows behave as before.
  • on: until without until is a validation error.
  • An until expression error still counts as "not yet", since the call itself succeeded.

A per-tool requirement (a profile forcing on: until on every step that calls a tool) is not included: tools are declared per flow, not per step, so Lest cannot tell which step calls which tool.

Tests

  • retry_on_until_stops_at_the_first_failed_attempt: the second attempt fails, the step fails at attempt 2 with that attempt's error, and one retry event is emitted.
  • retry_on_until_keeps_polling_while_the_condition_is_false: polls to success, and fails when attempts run out.
  • retry_by_default_still_repeats_a_failed_attempt: the default is unchanged.
  • retry_on_until_needs_a_condition (validation).

make check passes except for timing-based tests (cancel at 500 ms, parallel group, service shutdown) that fail intermittently on a heavily loaded machine. A different one fails on each run, none touch retry, and the runner suite passes with --test-threads=2.

A poll that calls a system which must not see a repeated request can now stop at the first failed attempt instead of retrying it. The default keeps retrying failed attempts.
@piekstra

Copy link
Copy Markdown
Member Author

Review of the diff, with dispositions:

  • Agent guide did not mention on: until. lest docs agent is what authoring agents read. Fixed in a3dffd1.
  • on: until without until. At run time it would fall back to retrying failures. Validation rejects it, so the runtime path is unreachable. No change.
  • Status of a stopped attempt. It keeps the attempt's own status (Failed for a non-zero exit or an unmet expect, Errored for a spawn error) and headline, the same as a step without retry. No change.
  • Per-tool enforcement. Not added. Tools are declared per flow, so Lest cannot tell which step calls which tool. Noted in the PR body.
  • Flaky tests. cancel_stops_steps_but_runs_finally_and_cleanup, parallel_group_runs_concurrently and services_that_ignore_term_are_killed_and_logs_are_redacted also fail on unmodified main at this machine's load, so they are not from this change. Left for a separate fix.

@piekstra piekstra closed this Oct 26, 2026
@piekstra piekstra reopened this Oct 26, 2026
@piekstra
piekstra marked this pull request as ready for review October 26, 2026 17:39
@piekstra
piekstra merged commit 2dd3a86 into main Oct 26, 2026
9 of 10 checks passed
@piekstra
piekstra deleted the piekstra/retry-poll-only branch October 26, 2026 18:07
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