buz 2.15.6__py3-none-any.whl → 2.15.8rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- buz/event/infrastructure/buz_kafka/base_buz_aiokafka_async_consumer.py +51 -21
- buz/kafka/infrastructure/aiokafka/aiokafka_consumer.py +2 -5
- {buz-2.15.6.dist-info → buz-2.15.8rc1.dist-info}/METADATA +1 -1
- {buz-2.15.6.dist-info → buz-2.15.8rc1.dist-info}/RECORD +6 -6
- {buz-2.15.6.dist-info → buz-2.15.8rc1.dist-info}/LICENSE +0 -0
- {buz-2.15.6.dist-info → buz-2.15.8rc1.dist-info}/WHEEL +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
1
2
|
import json
|
|
2
3
|
import traceback
|
|
3
4
|
from abc import abstractmethod
|
|
@@ -39,6 +40,7 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
|
|
|
39
40
|
__SECONDS_BETWEEN_EXECUTIONS_IF_THERE_ARE_NO_TASKS_IN_THE_QUEUE = 1
|
|
40
41
|
__SECONDS_BETWEEN_POLLS_IF_THERE_ARE_TASKS_IN_THE_QUEUE = 1
|
|
41
42
|
__SECONDS_BETWEEN_POLLS_IF_THERE_ARE_NO_NEW_TASKS = 1
|
|
43
|
+
__SECONDS_TO_WAIT_BETWEEN_REBALANCING_IN_PROGRESS = 0.1
|
|
42
44
|
__MAX_NUMBER_OF_CONCURRENT_POLLING_TASKS = 20
|
|
43
45
|
|
|
44
46
|
def __init__(
|
|
@@ -103,8 +105,9 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
|
|
|
103
105
|
)
|
|
104
106
|
self.__wait_for_connection_to_cluster_ms: Optional[int] = wait_for_connection_to_cluster_ms
|
|
105
107
|
self.__polling_tasks_semaphore = Semaphore(self.__max_number_of_concurrent_polling_tasks)
|
|
106
|
-
self.
|
|
108
|
+
self.__consumer_and_partition_mutex: dict[str, Lock] = defaultdict(Lock)
|
|
107
109
|
self.__is_worked_initialized = False
|
|
110
|
+
self.__number_of_rebalancing_processes_in_progress: int = 0
|
|
108
111
|
|
|
109
112
|
async def configure_http_check_server(self, health_check_port: int) -> web.TCPSite:
|
|
110
113
|
self._logger.info(f"Starting health check server on port {health_check_port}")
|
|
@@ -114,7 +117,7 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
|
|
|
114
117
|
|
|
115
118
|
runner = web.AppRunner(app)
|
|
116
119
|
await runner.setup()
|
|
117
|
-
site = web.TCPSite(runner, "
|
|
120
|
+
site = web.TCPSite(runner, "0.0.0.0", health_check_port)
|
|
118
121
|
await site.start()
|
|
119
122
|
return site
|
|
120
123
|
|
|
@@ -156,16 +159,13 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
|
|
|
156
159
|
f" - Session timeout ms: {self.__session_timeout_ms}\n"
|
|
157
160
|
f" - Max poll interval ms: {self.__max_poll_interval_ms}\n"
|
|
158
161
|
f" - Heartbeat interval ms: {self.__heartbeat_interval_ms}\n"
|
|
159
|
-
f" - Seconds between executions if there are no tasks in the queue: "
|
|
160
|
-
f"{self.
|
|
161
|
-
f" - Seconds between polls if there are
|
|
162
|
-
f"{self.__seconds_between_polls_if_there_are_tasks_in_the_queue}\n"
|
|
163
|
-
f" - Seconds between polls if there are no new tasks: "
|
|
164
|
-
f"{self.__seconds_between_polls_if_there_are_no_new_tasks}\n"
|
|
162
|
+
f" - Seconds between executions if there are no tasks in the queue: {self.__seconds_between_executions_if_there_are_no_tasks_in_the_queue}\n"
|
|
163
|
+
f" - Seconds between polls if there are tasks in the queue: {self.__seconds_between_polls_if_there_are_tasks_in_the_queue}\n"
|
|
164
|
+
f" - Seconds between polls if there are no new tasks: {self.__seconds_between_polls_if_there_are_no_new_tasks}\n"
|
|
165
165
|
f" - Max number of concurrent polling tasks: {self.__max_number_of_concurrent_polling_tasks}\n"
|
|
166
166
|
f" - Wait for connection to cluster ms: {self.__wait_for_connection_to_cluster_ms}\n"
|
|
167
167
|
f" - Health check port: {self.__health_check_port}\n"
|
|
168
|
-
f" - Number of subscribers: {len(self.__subscribers)}"
|
|
168
|
+
f" - Number of subscribers: {len(self.__subscribers)}",
|
|
169
169
|
)
|
|
170
170
|
|
|
171
171
|
async def __handle_graceful_stop(self, worker_errors: tuple[Optional[Exception], Optional[Exception]]) -> None:
|
|
@@ -234,7 +234,7 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
|
|
|
234
234
|
self.__queue_per_consumer_mapper[kafka_consumer] = InMemoryMultiqueueRepository()
|
|
235
235
|
|
|
236
236
|
self._logger.info(
|
|
237
|
-
f"
|
|
237
|
+
f"Initializing consumer group: '{kafka_consumer.get_consumer_group()}' subscribed to the topics: '{kafka_consumer.get_topics()}'"
|
|
238
238
|
)
|
|
239
239
|
|
|
240
240
|
await kafka_consumer.init()
|
|
@@ -306,29 +306,59 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
|
|
|
306
306
|
last_consumer, _ = next(consumer_queues_cyclic_iterator)
|
|
307
307
|
|
|
308
308
|
while not self.__should_stop.is_set():
|
|
309
|
+
if self.is_rebalancing_in_progress():
|
|
310
|
+
self._logger.info("Waiting for rebalancing")
|
|
311
|
+
await sleep(self.__SECONDS_TO_WAIT_BETWEEN_REBALANCING_IN_PROGRESS)
|
|
312
|
+
continue
|
|
313
|
+
|
|
309
314
|
if await self.__all_queues_are_empty():
|
|
310
315
|
await sleep(self.__seconds_between_executions_if_there_are_no_tasks_in_the_queue)
|
|
311
316
|
continue
|
|
312
317
|
|
|
313
|
-
|
|
314
|
-
|
|
318
|
+
consumer: Optional[AIOKafkaConsumer] = None
|
|
319
|
+
|
|
320
|
+
while consumer != last_consumer:
|
|
321
|
+
consumer, queue = next(consumer_queues_cyclic_iterator)
|
|
322
|
+
kafka_poll_record = queue.pop()
|
|
323
|
+
|
|
324
|
+
if kafka_poll_record is not None:
|
|
325
|
+
consuming_task = ConsumingTask(consumer, kafka_poll_record)
|
|
326
|
+
async with self.__get_partition_mutex(
|
|
327
|
+
consumer_fqn=consuming_task.consumer.get_consumer_group(),
|
|
328
|
+
partition=kafka_poll_record.partition,
|
|
329
|
+
):
|
|
330
|
+
yield consuming_task
|
|
315
331
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
kafka_poll_record = queue.pop()
|
|
332
|
+
last_consumer = consumer
|
|
333
|
+
break
|
|
319
334
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
break
|
|
335
|
+
def __get_partition_mutex(self, consumer_fqn: str, partition: int) -> Lock:
|
|
336
|
+
mutex_key = f"consumer_{consumer_fqn}_partition_{partition}"
|
|
337
|
+
return self.__consumer_and_partition_mutex[mutex_key]
|
|
324
338
|
|
|
325
339
|
async def __all_queues_are_empty(self) -> bool:
|
|
326
340
|
return all([queue.is_totally_empty() for queue in self.__queue_per_consumer_mapper.values()])
|
|
327
341
|
|
|
328
342
|
async def __on_partition_revoked(self, consumer: AIOKafkaConsumer, topics_partitions: set[TopicPartition]) -> None:
|
|
329
|
-
|
|
330
|
-
|
|
343
|
+
self._logger.info(f"rebalancing in progress, revoking partitions {topics_partitions}")
|
|
344
|
+
|
|
345
|
+
self.increase_number_of_rebalancing_in_progress()
|
|
346
|
+
for topic_partition in topics_partitions:
|
|
347
|
+
async with self.__get_partition_mutex(
|
|
348
|
+
consumer_fqn=consumer.get_consumer_group(),
|
|
349
|
+
partition=topic_partition.partition,
|
|
350
|
+
):
|
|
331
351
|
self.__queue_per_consumer_mapper[consumer].clear(topic_partition)
|
|
352
|
+
self.decrease_number_of_rebalancing_in_progress()
|
|
353
|
+
|
|
354
|
+
def increase_number_of_rebalancing_in_progress(self) -> None:
|
|
355
|
+
self.__number_of_rebalancing_processes_in_progress += 1
|
|
356
|
+
|
|
357
|
+
def decrease_number_of_rebalancing_in_progress(self) -> None:
|
|
358
|
+
self.__number_of_rebalancing_processes_in_progress -= 1
|
|
359
|
+
|
|
360
|
+
def is_rebalancing_in_progress(self) -> bool:
|
|
361
|
+
return self.__number_of_rebalancing_processes_in_progress > 0
|
|
332
362
|
|
|
333
363
|
def request_stop(self) -> None:
|
|
334
364
|
self.__should_stop.set()
|
|
@@ -152,7 +152,7 @@ class AIOKafkaConsumer:
|
|
|
152
152
|
),
|
|
153
153
|
)
|
|
154
154
|
|
|
155
|
-
self.__logger.info(f"
|
|
155
|
+
self.__logger.info(f"Initializing connection of consumer with group_id={self.__consumer_group}")
|
|
156
156
|
|
|
157
157
|
if self.__wait_for_connection_to_cluster_ms is not None:
|
|
158
158
|
await asyncio.wait_for(self.__consumer.start(), self.__wait_for_connection_to_cluster_ms / 1000)
|
|
@@ -163,10 +163,7 @@ class AIOKafkaConsumer:
|
|
|
163
163
|
self,
|
|
164
164
|
topics_partitions: set[TopicPartition],
|
|
165
165
|
) -> None:
|
|
166
|
-
|
|
167
|
-
self.__consumer.pause(*topics_partitions)
|
|
168
|
-
await self.__consumer.seek_to_committed(*topics_partitions)
|
|
169
|
-
self.__consumer.resume(*topics_partitions)
|
|
166
|
+
return
|
|
170
167
|
|
|
171
168
|
async def __on_partitions_revoked(
|
|
172
169
|
self,
|
|
@@ -47,7 +47,7 @@ buz/event/exceptions/worker_execution_exception.py,sha256=6mgztvXOCG_9VZ_Jptkk72
|
|
|
47
47
|
buz/event/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
buz/event/infrastructure/buz_kafka/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
49
|
buz/event/infrastructure/buz_kafka/async_buz_kafka_event_bus.py,sha256=SyLblUVlwWOaNfZzK7vL6Ee4m-85vZVCH0rjOgqVAww,4913
|
|
50
|
-
buz/event/infrastructure/buz_kafka/base_buz_aiokafka_async_consumer.py,sha256=
|
|
50
|
+
buz/event/infrastructure/buz_kafka/base_buz_aiokafka_async_consumer.py,sha256=13CqXqXk_1tgVJ6SpXpW4nr2SMA7ujpm8l4q3Yhtdsg,20179
|
|
51
51
|
buz/event/infrastructure/buz_kafka/buz_aiokafka_async_consumer.py,sha256=lLHUnf9DpfAyB0PN7oBjn-Eyyl0zCHsSnrb6QUigruk,6345
|
|
52
52
|
buz/event/infrastructure/buz_kafka/buz_aiokafka_multi_threaded_consumer.py,sha256=CiuNTns6eifR2JNGhXGNTdWURu-IQVIioe5n_pMSt9s,6288
|
|
53
53
|
buz/event/infrastructure/buz_kafka/buz_kafka_event_bus.py,sha256=ymRSvcYVgbVCPgHN6rMBVBHQ5heCSwCDl6EffyqGVX8,4601
|
|
@@ -164,7 +164,7 @@ buz/kafka/domain/services/kafka_admin_test_client.py,sha256=91l_vFIo1yhJLQQCC_Om
|
|
|
164
164
|
buz/kafka/domain/services/kafka_producer.py,sha256=8bLTV328orrPHcARzkc6no4vyJzrArVtCsjmSRXDjos,506
|
|
165
165
|
buz/kafka/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
166
166
|
buz/kafka/infrastructure/aiokafka/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
167
|
-
buz/kafka/infrastructure/aiokafka/aiokafka_consumer.py,sha256=
|
|
167
|
+
buz/kafka/infrastructure/aiokafka/aiokafka_consumer.py,sha256=9ORj5couBePn5LtIlTXUlMF2hSOuZ5vmgG0RUbw-BVM,8792
|
|
168
168
|
buz/kafka/infrastructure/aiokafka/aiokafka_producer.py,sha256=LteHKIHpT6MKplwmwsPYMsd2GWNJCzus65XDHCIdoN8,3823
|
|
169
169
|
buz/kafka/infrastructure/aiokafka/rebalance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
170
170
|
buz/kafka/infrastructure/aiokafka/rebalance/kafka_callback_rebalancer.py,sha256=3l7NkTrCt3rBktVIS73cTmCOvv6eFguoCbGMYIUfCFc,1774
|
|
@@ -250,7 +250,7 @@ buz/serializer/message_to_json_bytes_serializer.py,sha256=RGZJ64t4t4Pz2FCASZZCv-
|
|
|
250
250
|
buz/wrapper/__init__.py,sha256=GnRdJFcncn-qp0hzDG9dBHLmTJSbHFVjE_yr-MdW_n4,77
|
|
251
251
|
buz/wrapper/async_to_sync.py,sha256=OfK-vrVUhuN-LLLvekLdMbQYtH0ue5lfbvuasj6ovMI,698
|
|
252
252
|
buz/wrapper/event_loop.py,sha256=pfBJ1g-8A2a3YgW8Gf9Fg0kkewoh3-wgTy2KIFDyfHk,266
|
|
253
|
-
buz-2.15.
|
|
254
|
-
buz-2.15.
|
|
255
|
-
buz-2.15.
|
|
256
|
-
buz-2.15.
|
|
253
|
+
buz-2.15.8rc1.dist-info/LICENSE,sha256=Jytu2S-2SPEgsB0y6BF-_LUxIWY7402fl0JSh36TLZE,1062
|
|
254
|
+
buz-2.15.8rc1.dist-info/METADATA,sha256=EcA5CSIiqruT_bLWz0GS6LaFdRbbbJiG_Stg9zspIug,1600
|
|
255
|
+
buz-2.15.8rc1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
256
|
+
buz-2.15.8rc1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|