-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Python EventHubs load balancing #6901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
3a32907
39b1b86
17f5153
04ef548
9be1741
1b5753c
b4b77f9
1787fdd
c2d0155
1074385
386baf0
1afbf0c
c126bea
40c7f03
cf22c7c
c7440b2
fa804f4
470cf7e
e5f3b50
8343876
66c5b31
bcd851a
d740bb0
aad6978
a55dc13
a339985
9102713
278592c
665f28c
0060f9d
7b4273a
bdf97c8
02a4daf
a9446de
8dfdec9
2aace82
36ba0a3
7f95d9e
f5870af
f30d143
893bee0
4b41fa5
fef0551
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,7 +56,9 @@ async def process_events(self, events, partition_context): | |
| def __init__( | ||
| self, eventhub_client: EventHubClient, consumer_group_name: str, | ||
| partition_processor_factory: Callable[..., PartitionProcessor], | ||
| partition_manager: PartitionManager, **kwargs | ||
| partition_manager: PartitionManager, *, | ||
| initial_event_position: EventPosition = EventPosition("-1"), polling_interval: float = 10.0 | ||
|
|
||
| ): | ||
| """ | ||
| Instantiate an EventProcessor. | ||
|
|
@@ -84,14 +86,9 @@ def __init__( | |
| self._eventhub_name = eventhub_client.eh_name | ||
| self._partition_processor_factory = partition_processor_factory | ||
| self._partition_manager = partition_manager | ||
| self._initial_event_position = kwargs.get("initial_event_position", "-1") | ||
| # TODO: initial position provider will be a callable | ||
| # so users can create initial event position for every partition | ||
| self._max_batch_size = eventhub_client.config.max_batch_size | ||
| self._receive_timeout = eventhub_client.config.receive_timeout | ||
| self._polling_interval = kwargs.get("polling_interval", 10) | ||
| self._initial_event_position = initial_event_position # will be replaced by reset event position in preview 4 | ||
| self._polling_interval = polling_interval | ||
| self._ownership_timeout = self._polling_interval * 2 | ||
| # TODO: Team haven't decided if this is a separate argument | ||
| self._tasks = {} # type: Dict[str, asyncio.Task] | ||
| self._id = str(uuid.uuid4()) | ||
| self._running = False | ||
|
|
@@ -122,18 +119,19 @@ async def start(self): | |
| try: | ||
| claimed_ownership_list = await ownership_manager.claim_ownership() | ||
| except Exception as err: | ||
| log.exception("An exception occurred during balancing and claiming ownership for eventhub %r " | ||
| "consumer group %r. Retrying after %r seconds", | ||
| self._eventhub_name, self._consumer_group_name, self._polling_interval, exc_info=err) | ||
| log.warning("An exception (%r) occurred during balancing and claiming ownership for eventhub %r " | ||
| "consumer group %r. Retrying after %r seconds", | ||
| err, self._eventhub_name, self._consumer_group_name, self._polling_interval) | ||
| await asyncio.sleep(self._polling_interval) | ||
| continue | ||
|
|
||
| to_cancel_list = self._tasks.keys() | ||
| if claimed_ownership_list: | ||
| claimed_partition_ids = [x["partition_id"] for x in claimed_ownership_list] | ||
| to_cancel_list = self._tasks.keys() - claimed_partition_ids | ||
| self._create_tasks_for_claimed_ownership(claimed_ownership_list) | ||
| else: | ||
| log.warning("EventProcessor %r hasn't claimed an ownership. It keeps claiming.", self._id) | ||
| to_cancel_list = self._tasks.keys() | ||
| log.info("EventProcessor %r hasn't claimed an ownership. It keeps claiming.", self._id) | ||
| if to_cancel_list: | ||
| self._cancel_tasks_for_partitions(to_cancel_list) | ||
| log.info("EventProcesor %r has cancelled partitions %r", self._id, to_cancel_list) | ||
|
|
@@ -153,7 +151,7 @@ async def stop(self): | |
| _, task = self._tasks.popitem() | ||
| task.cancel() | ||
| log.info("EventProcessor %r has been cancelled", self._id) | ||
| await asyncio.sleep(2) # give some time to finish after cancelled | ||
| await asyncio.sleep(2) # give some time to finish after cancelled. | ||
|
|
||
| def _cancel_tasks_for_partitions(self, to_cancel_partitions): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would invert this and pass in the currently claimed partitions. This way the use of self._tasks is more centralized/less spread out.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm going to keep the code for now to save time for other more important stuffs and come back to this during preview 4 coding |
||
| for partition_id in to_cancel_partitions: | ||
|
|
@@ -181,23 +179,22 @@ async def _receive(self, ownership): | |
| owner_id, | ||
| self._partition_manager | ||
| ) | ||
| partition_processor.eventhub_name = ownership | ||
| partition_consumer = self._eventhub_client.create_consumer( | ||
| consumer_group_name, | ||
| partition_id, | ||
| EventPosition(ownership.get("offset", self._initial_event_position)) | ||
| EventPosition(ownership.get("offset", self._initial_event_position.value)) | ||
| ) | ||
|
|
||
| async def process_error(err): | ||
| log.error( | ||
| log.warning( | ||
| "PartitionProcessor of EventProcessor instance %r of eventhub %r partition %r consumer group %r" | ||
| " has met an error. The exception is %r.", | ||
| owner_id, eventhub_name, partition_id, consumer_group_name, err | ||
| ) | ||
| try: | ||
| await partition_processor.process_error(err, partition_context) | ||
| except Exception as err_again: # pylint:disable=broad-except | ||
| log.error( | ||
| log.warning( | ||
| "PartitionProcessor of EventProcessor instance %r of eventhub %r partition %r consumer group %r" | ||
| " has another error during running process_error(). The exception is %r.", | ||
| owner_id, eventhub_name, partition_id, consumer_group_name, err_again | ||
|
|
@@ -212,7 +209,7 @@ async def close(reason): | |
| try: | ||
| await partition_processor.close(reason, partition_context) | ||
| except Exception as err: # pylint:disable=broad-except | ||
| log.error( | ||
| log.warning( | ||
| "PartitionProcessor of EventProcessor instance %r of eventhub %r partition %r consumer group %r" | ||
| " has an error during running close(). The exception is %r.", | ||
| owner_id, eventhub_name, partition_id, consumer_group_name, err | ||
|
|
@@ -222,7 +219,7 @@ async def close(reason): | |
| while True: | ||
| try: | ||
| await partition_processor.initialize(partition_context) | ||
| events = await partition_consumer.receive(timeout=self._receive_timeout) | ||
| events = await partition_consumer.receive() | ||
| await partition_processor.process_events(events, partition_context) | ||
| except asyncio.CancelledError: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am very concerned about the fact that we are not re-raising the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed "break" to "raise" for this "except asyncio.CancelledError:" block |
||
| log.info( | ||
|
|
@@ -237,21 +234,18 @@ async def close(reason): | |
| await close(CloseReason.SHUTDOWN) | ||
| else: | ||
| await close(CloseReason.OWNERSHIP_LOST) | ||
| # TODO: release the ownership immediately via partition manager in preview 4 | ||
| break | ||
| except EventHubError as eh_err: | ||
| await process_error(eh_err) | ||
| await close(CloseReason.EVENTHUB_EXCEPTION) | ||
| # An EventProcessor will pick up this partition again after the ownership is released | ||
| # TODO: release the ownership immediately via partition manager in preview 4 | ||
| break | ||
| except OwnershipLostError: | ||
| await close(CloseReason.OWNERSHIP_LOST) | ||
| break | ||
| except Exception as other_error: # pylint:disable=broad-except | ||
| await process_error(other_error) | ||
| await close(CloseReason.PROCESS_EVENTS_ERROR) | ||
| # TODO: release the ownership immediately via partition manager in preview 4 | ||
| break | ||
| finally: | ||
| await partition_consumer.close() | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a comment to describe what it is doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment