Skip to content

fix(operators): reset retry budget per subscription to fix retry+repeat#765

Merged
dbrattli merged 2 commits intomasterfrom
repo-assist/fix-issue-712-retry-resubscription-2b9941042da6d10e
Apr 20, 2026
Merged

fix(operators): reset retry budget per subscription to fix retry+repeat#765
dbrattli merged 2 commits intomasterfrom
repo-assist/fix-issue-712-retry-resubscription-2b9941042da6d10e

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Summary

Fixes retry(n) interacting incorrectly with repeat() (issue #712).

Root Cause

The retry generator (range(n) or infinite()) was created once at observable creation time and shared across all subscriptions:

# Before — generator created once, shared across resubscriptions
gen = range(retry_count)
return reactivex.catch_with_iterable(source for _ in gen)

catch_with_iterable stores iter(sources) at construction, so the iterator is shared. When repeat() resubscribes to retry(n), the iterator may already be fully consumed, causing catch_with_iterable to immediately call observer.on_completed() without subscribing to the source. This triggered repeat() again in a tight loop that produced no values after the nth subscription.

Fix

Move the generator creation inside the subscribe closure so each subscription gets a fresh retry budget:

def subscribe(observer, scheduler_=None):
    # Fresh generator on every subscription
    gen = infinite() if retry_count is None else range(retry_count)
    return reactivex.catch_with_iterable(source for _ in gen).subscribe(
        observer, scheduler=scheduler_
    )
return Observable(subscribe)

This matches the expected ReactiveX semantics: retry(n) means "on error, resubscribe up to n times per subscription attempt". Each invocation from repeat() is a new subscription and should start with a full retry allowance.

Changes

  • reactivex/operators/_retry.py: wrap logic in subscribe closure
  • tests/test_observable/test_retry.py: add regression test for retry(n) + repeat()
  • changes.md: add changelog entry; also resolve lingering merge-conflict markers

Testing

All 10 tests pass (pytest tests/test_observable/test_retry.py). The new test test_retry_with_count_combined_with_repeat reproduces the exact scenario from issue #712 and verifies the fix.

Closes #712

Note

🔒 Integrity filter blocked 67 items

The following items were blocked because they don't meet the GitHub integrity level.

  • #749 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #748 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #742 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #736 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #711 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #700 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #698 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #634 list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • Missing tap operator #750 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • Python 3.14 Support #737 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • AsyncIOScheduler.now returns a datetime in 1970. #734 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • Offering help with Unit Tests #730 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • Schedulers using different now() implementation breaks schedule_absolute() compatibility. #724 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • Lack of concat_map / concat_all #723 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • Concurrent Execution Not Working as Expected with RxPY ThreadPoolScheduler #713 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • switch_map() operator not listed in documentation #710 list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • ... and 51 more items

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Repo Assist · ● 3.3M ·

@coveralls
Copy link
Copy Markdown

coveralls commented Apr 20, 2026

Coverage Status

No base build to compare — repo-assist/fix-issue-712-retry-resubscription-2b9941042da6d10e into master

@dbrattli dbrattli changed the title [Repo Assist] fix(operators): reset retry budget per subscription to fix retry+repeat fix(operators): reset retry budget per subscription to fix retry+repeat Apr 20, 2026
The retry(n) generator was created once at observable creation time
and shared across all subscriptions. When combined with repeat(), the
retry pool was exhausted after n total subscriptions regardless of
errors, causing repeat() to resubscribe to an empty generator that
immediately completed.

Fix: create the generator inside the subscribe closure so each
subscription gets a fresh retry budget. This matches the expected
ReactiveX semantics where retry(n) means 'on error, resubscribe up
to n times per subscription'.

Closes #712

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dbrattli dbrattli force-pushed the repo-assist/fix-issue-712-retry-resubscription-2b9941042da6d10e branch from ae29c2b to 7820458 Compare April 20, 2026 21:52
@dbrattli dbrattli marked this pull request as ready for review April 20, 2026 21:52
@dbrattli dbrattli merged commit c3f19d5 into master Apr 20, 2026
44 checks passed
@dbrattli dbrattli deleted the repo-assist/fix-issue-712-retry-resubscription-2b9941042da6d10e branch April 20, 2026 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

operators.retry(n) interferes with non-erroring repeats

2 participants