buz 2.15.10rc1__py3-none-any.whl → 2.15.10rc3__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.
@@ -226,6 +226,7 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
226
226
  logger=self._logger,
227
227
  kafka_admin_client=self.__kafka_admin_client,
228
228
  auto_create_topic_configuration=self.__auto_create_topic_configuration,
229
+ on_partition_assigned=self.__on_partition_assigned,
229
230
  on_partition_revoked=self.__on_partition_revoked,
230
231
  session_timeout_ms=self.__session_timeout_ms,
231
232
  max_poll_interval_ms=self.__max_poll_interval_ms,
@@ -328,36 +329,41 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
328
329
 
329
330
  while consumer != last_consumer:
330
331
  consumer, queue = next(consumer_queues_cyclic_iterator)
331
- kafka_poll_record = queue.pop()
332
+ async with self.__get_consumer_mutex(
333
+ consumer_fqn=consumer.get_consumer_group(),
334
+ ):
335
+ kafka_poll_record = queue.pop()
332
336
 
333
- if kafka_poll_record is not None:
334
- consuming_task = ConsumingTask(consumer, kafka_poll_record)
335
- async with self.__get_partition_mutex(
336
- consumer_fqn=consuming_task.consumer.get_consumer_group(),
337
- partition=kafka_poll_record.partition,
338
- ):
339
- yield consuming_task
337
+ if kafka_poll_record is not None:
338
+ yield ConsumingTask(consumer, kafka_poll_record)
340
339
 
341
340
  last_consumer = consumer
342
341
  break
343
342
 
344
- def __get_partition_mutex(self, consumer_fqn: str, partition: int) -> Lock:
345
- mutex_key = f"consumer_{consumer_fqn}_partition_{partition}"
343
+ def __get_consumer_mutex(self, consumer_fqn: str) -> Lock:
344
+ mutex_key = f"consumer_{consumer_fqn}"
346
345
  return self.__consumer_and_partition_mutex[mutex_key]
347
346
 
348
347
  async def __all_queues_are_empty(self) -> bool:
349
348
  return all([queue.is_totally_empty() for queue in self.__queue_per_consumer_mapper.values()])
350
349
 
350
+ async def __on_partition_assigned(self, consumer: AIOKafkaConsumer, topics_partitions: set[TopicPartition]) -> None:
351
+ self._logger.info(
352
+ f"rebalancing in progress, assigning partitions {topics_partitions} to consumer {consumer.get_consumer_group()}"
353
+ )
354
+
351
355
  async def __on_partition_revoked(self, consumer: AIOKafkaConsumer, topics_partitions: set[TopicPartition]) -> None:
352
- self._logger.info(f"rebalancing in progress, revoking partitions {topics_partitions}")
356
+ self._logger.info(
357
+ f"rebalancing in progress, revoking partitions {topics_partitions} from consumer {consumer.get_consumer_group()}"
358
+ )
353
359
 
354
360
  self.increase_number_of_rebalancing_in_progress()
355
- for topic_partition in topics_partitions:
356
- async with self.__get_partition_mutex(
357
- consumer_fqn=consumer.get_consumer_group(),
358
- partition=topic_partition.partition,
359
- ):
361
+ async with self.__get_consumer_mutex(
362
+ consumer_fqn=consumer.get_consumer_group(),
363
+ ):
364
+ for topic_partition in topics_partitions:
360
365
  self.__queue_per_consumer_mapper[consumer].clear(topic_partition)
366
+
361
367
  self.decrease_number_of_rebalancing_in_progress()
362
368
 
363
369
  def increase_number_of_rebalancing_in_progress(self) -> None:
@@ -374,8 +380,7 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
374
380
  self._logger.info("Worker stop requested. Waiting for finalize the current task")
375
381
 
376
382
  async def __manage_kafka_consumers_stopping(self) -> None:
377
- for kafka_consumer in self.__queue_per_consumer_mapper.keys():
378
- await kafka_consumer.stop()
383
+ await gather(*[kafka_consumer.stop() for kafka_consumer in self.__queue_per_consumer_mapper.keys()])
379
384
 
380
385
  async def __health_check(self) -> web.Response:
381
386
  health_information = {
@@ -4,7 +4,7 @@ import asyncio
4
4
  from logging import Logger
5
5
  from typing import Awaitable, Callable, Optional, Sequence, cast
6
6
 
7
- from aiokafka import AIOKafkaConsumer as AIOKafkaNativeConsumer, TopicPartition, OffsetAndMetadata
7
+ from aiokafka import AIOKafkaConsumer as AIOKafkaNativeConsumer, ConsumerRecord, TopicPartition, OffsetAndMetadata
8
8
  from aiokafka.helpers import create_ssl_context
9
9
 
10
10
  from buz.event.infrastructure.buz_kafka.exceptions.kafka_event_bus_config_not_valid_exception import (
@@ -26,6 +26,7 @@ from buz.kafka.infrastructure.aiokafka.translators.consumer_initial_offset_posit
26
26
 
27
27
  class AIOKafkaConsumer:
28
28
  __DEFAULT_POLL_TIMEOUT_MS = 0
29
+ __DEFAULT_ASYNC_FUNCTION_TIMEOUT_MS = 3000
29
30
 
30
31
  def __init__(
31
32
  self,
@@ -41,6 +42,7 @@ class AIOKafkaConsumer:
41
42
  max_poll_interval_ms: int,
42
43
  heartbeat_interval_ms: int,
43
44
  on_partition_revoked: Callable[[AIOKafkaConsumer, set[TopicPartition]], Awaitable[None]],
45
+ on_partition_assigned: Callable[[AIOKafkaConsumer, set[TopicPartition]], Awaitable[None]],
44
46
  auto_create_topic_configuration: Optional[AutoCreateTopicConfiguration] = None,
45
47
  wait_for_connection_to_cluster_ms: Optional[int] = None,
46
48
  group_instance_id: Optional[str] = None,
@@ -55,6 +57,7 @@ class AIOKafkaConsumer:
55
57
  self.__session_timeout_ms = session_timeout_ms
56
58
  self.__auto_create_topic_configuration = auto_create_topic_configuration
57
59
  self.__on_partitions_revoked_callback = on_partition_revoked
60
+ self.__on_partitions_assigned_callback = on_partition_assigned
58
61
  self.__max_poll_interval_ms = max_poll_interval_ms
59
62
  self.__heartbeat_interval_ms = heartbeat_interval_ms
60
63
  self.__wait_for_connection_to_cluster_ms = wait_for_connection_to_cluster_ms
@@ -166,7 +169,7 @@ class AIOKafkaConsumer:
166
169
  self,
167
170
  topics_partitions: set[TopicPartition],
168
171
  ) -> None:
169
- return
172
+ await self.__on_partitions_assigned_callback(self, topics_partitions)
170
173
 
171
174
  async def __on_partitions_revoked(
172
175
  self,
@@ -177,14 +180,15 @@ class AIOKafkaConsumer:
177
180
  async def poll(
178
181
  self,
179
182
  *,
180
- timeout_ms: int = __DEFAULT_POLL_TIMEOUT_MS,
181
183
  number_of_messages_to_poll: Optional[int] = None,
182
184
  ) -> list[KafkaPollRecord]:
183
- poll_results = await self.__consumer.getmany(
184
- timeout_ms=timeout_ms,
185
+ poll_results = await self.__get_many(
185
186
  max_records=number_of_messages_to_poll,
186
187
  )
187
188
 
189
+ if poll_results is None:
190
+ return []
191
+
188
192
  results = [
189
193
  cast(KafkaPollRecord, consumer_record)
190
194
  for consumer_records in poll_results.values()
@@ -193,6 +197,19 @@ class AIOKafkaConsumer:
193
197
 
194
198
  return results
195
199
 
200
+ async def __get_many(
201
+ self,
202
+ max_records: Optional[int] = None,
203
+ ) -> Optional[dict[TopicPartition, list[ConsumerRecord]]]:
204
+ try:
205
+ return await asyncio.wait_for(
206
+ self.__consumer.getmany(timeout_ms=self.__DEFAULT_POLL_TIMEOUT_MS, max_records=max_records),
207
+ timeout=self.__DEFAULT_ASYNC_FUNCTION_TIMEOUT_MS / 1000,
208
+ )
209
+ except asyncio.TimeoutError:
210
+ self.__logger.debug("Timeout while polling")
211
+ return None
212
+
196
213
  async def commit_poll_record(self, poll_record: KafkaPollRecord) -> None:
197
214
  topic_partition = TopicPartition(topic=poll_record.topic, partition=poll_record.partition)
198
215
  offset = {topic_partition: OffsetAndMetadata(poll_record.offset + 1, "")}
@@ -201,4 +218,13 @@ class AIOKafkaConsumer:
201
218
 
202
219
  async def stop(self) -> None:
203
220
  self.__logger.info(f"Closing connection of consumer with group_id={self.__consumer_group}")
204
- await self.__consumer.stop()
221
+
222
+ self.__consumer.unsubscribe()
223
+
224
+ try:
225
+ await asyncio.wait_for(
226
+ self.__consumer.stop(),
227
+ timeout=self.__DEFAULT_ASYNC_FUNCTION_TIMEOUT_MS / 1000,
228
+ )
229
+ except asyncio.TimeoutError:
230
+ self.__logger.debug("Timeout while stopping consumer")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: buz
3
- Version: 2.15.10rc1
3
+ Version: 2.15.10rc3
4
4
  Summary: Buz is a set of light, simple and extensible implementations of event, command and query buses.
5
5
  License: MIT
6
6
  Author: Luis Pintado Lozano
@@ -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=pQQf9ASWg_Y84BxHHATOqiewZA_Ty7Oja_kuvS7H9cw,20688
50
+ buz/event/infrastructure/buz_kafka/base_buz_aiokafka_async_consumer.py,sha256=M5mdbht294CE6UYtH7wfV9BoZTJIMLdyO9Wvb94PG_Q,20867
51
51
  buz/event/infrastructure/buz_kafka/buz_aiokafka_async_consumer.py,sha256=DRe3u69LD7Yt9WjA_hK_PRznM08_Mz4hxC_4poppjck,6446
52
52
  buz/event/infrastructure/buz_kafka/buz_aiokafka_multi_threaded_consumer.py,sha256=-pJVJq3b2SFmPT7SNmdPhqN2o64Hsjwds-shQ-Y7ytg,6389
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=5m9XfSRH15wNblqpb-l8cqqIEtDFbpwySzYK_hSuXc4,8952
167
+ buz/kafka/infrastructure/aiokafka/aiokafka_consumer.py,sha256=3-73e2CJhSjHONsCH_kZB1x5EwhnzLG2cCKGmkU4q0s,10008
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.10rc1.dist-info/LICENSE,sha256=Jytu2S-2SPEgsB0y6BF-_LUxIWY7402fl0JSh36TLZE,1062
254
- buz-2.15.10rc1.dist-info/METADATA,sha256=bUl0KIsBwcN6w-eRU9C5zf_ZTaGk2o8ZnECnaaVUkck,1601
255
- buz-2.15.10rc1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
256
- buz-2.15.10rc1.dist-info/RECORD,,
253
+ buz-2.15.10rc3.dist-info/LICENSE,sha256=Jytu2S-2SPEgsB0y6BF-_LUxIWY7402fl0JSh36TLZE,1062
254
+ buz-2.15.10rc3.dist-info/METADATA,sha256=RH1nBTDq2HcwS_3FwsmWp8zrw_hNop7_jJyRKmAY9e4,1601
255
+ buz-2.15.10rc3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
256
+ buz-2.15.10rc3.dist-info/RECORD,,