Skip to content

Python SDK: expose consumer shutdown and offset drain timeout #4165

Open

Description

@jiengup

Description

The Rust high-level consumer exposes an asynchronous shutdown() method that drains pending offset work, performs final commits when enabled, leaves the consumer group, and stops its connection watcher.

The Python IggyConsumer currently has no corresponding method. Its consumer_group() builder also does not expose the Rust builder's offset_drain_timeout, which controls how long shutdown waits for background offset tasks.

This covers B22 and the currently applicable part of B23 in the Python SDK parity work tracked in #3893.

The commit_failed_messages setting listed in B23 is not present in the current Rust SDK and should not be added to the Python API.

Affected area / component

Python SDK

Proposed solution

  • Add IggyConsumer.shutdown() as an asynchronous method that locks the wrapped Rust consumer, calls its shutdown(), and maps any error to RuntimeError.
  • Preserve the Rust method's idempotent behavior.
  • Add an optional offset_drain_timeout: datetime.timedelta | None argument to IggyClient.consumer_group().
  • When provided, convert it to IggyDuration and pass it to IggyConsumerBuilder::offset_drain_timeout().
  • When omitted, preserve the Rust builder default of five seconds.
  • Regenerate foreign/python/apache_iggy.pyi and document the supported shutdown call order.
  • Extend foreign/python/tests/test_consumer_group.py to verify:
    • A consumer can be shut down after its consumption loop exits.
    • Repeated shutdown calls succeed.
    • A custom offset-drain timeout is accepted and propagated.
    • Shutdown leaves a consumer group promptly so another member can receive its partitions.

Adding a replacement for the removed commit_failed_messages option is outside this issue.

Alternatives considered

Continue relying only on the asyncio.Event accepted by consume_messages(). That event stops one consumption loop but does not expose the Rust consumer's resource and offset cleanup operation.

Contribution

  • I'm willing to submit a pull request to implement this feature

Good first issue

  • I think this could be a good first issue for a new contributor

Activity

  1. dedsec-terminal commented on Sep 14, 2026

    @dedsec-terminal

    I would like to work on this. Opened #4184 with shutdown() and offset_drain_timeout for the Python consumer.

  2. dedsec-terminal commented on Sep 14, 2026

    @dedsec-terminal

    Could you assign this to me? I would like to pick this up.

  3. justinmclean commented on Sep 23, 2026

    @justinmclean
    Member

    Difficulty: medium. The change is in the PyO3 binding (foreign/python/src/consumer.rs), and the producer's shutdown() in producer.rs is a working pattern to follow. The tests in foreign/python/tests/ run against a real server. Please read CONTRIBUTING.md first, in particular that PRs must be built and tested locally before they're opened. This is open for anyone to pick up.

  4. shivaansh0610-LUFFY commented on Sep 24, 2026

    @shivaansh0610-LUFFY

    Hey @jiengup , I'd like to work on this too if it's still up for grabs - saw the note about producer.rs's shutdown() being the pattern to follow, makes sense as the template for locking the wrapped consumer and mapping errors to RuntimeError.

    Have gone through CONTRIBUTING.md, will run the full local check (fmt/clippy/test/machete/sort/typos) and have a server up for the foreign/python/tests suite before opening anything.

    Happy to let you pick whoever you'd rather go with if someone's further along already, just wanted to throw my hat in.

  5. slbotbm commented on Sep 24, 2026

    @slbotbm
    Contributor
  6. ParthibanRajasekaran commented on Oct 26, 2026

    @ParthibanRajasekaran
    Contributor

    @hubcio @justinmclean I noticed this issue is still open and that #4281 was closed after the earlier implementation became inactive.

    My understanding is that the Python SDK needs to expose the Rust consumer’s existing shutdown lifecycle, including draining pending offsets and leaving the consumer group, plus an optional offset_drain_timeout on consumer_group().

    In the current Python wrapper, consume_messages() holds the consumer mutex for the duration of the run, while the Rust IggyConsumer::shutdown() is intended to be called after consumption stops. Would the clean approach be to keep the existing asyncio.Event as the way to stop consume_messages(), then expose shutdown() for the final drain and group leave?

    That would avoid the deadlock concern from #4281 while staying consistent with the Rust consumer API. I would also add tests proving that the group membership is released and that the final offset is stored. Would you prefer that lifecycle, or would you rather see a separate cancellation path that allows shutdown() to interrupt an active consume_messages() task?

    If that direction sounds right, I’d be happy to take this issue and prepare a focused implementation :)

  7. hubcio commented on Oct 26, 2026

    @hubcio
    Contributor

    you can give it a shot. @slbotbm do u have any comment?

  8. slbotbm commented on Oct 26, 2026

    @slbotbm
    Contributor

    @ParthibanRajasekaran can go ahead with the implementation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

good first issueGood for newcomerspythonPull requests that update Python code

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions