buz 2.13.1rc6__tar.gz → 2.13.1rc8__tar.gz

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.
Files changed (236) hide show
  1. {buz-2.13.1rc6 → buz-2.13.1rc8}/PKG-INFO +1 -1
  2. {buz-2.13.1rc6 → buz-2.13.1rc8}/pyproject.toml +2 -1
  3. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/dlq_record.py +13 -0
  4. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/base_buz_aiokafka_async_consumer.py +55 -69
  5. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_kafka_event_bus.py +17 -12
  6. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/aiokafka_consumer.py +8 -2
  7. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/cdc/cdc_message.py +3 -1
  8. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/cdc/cdc_record_bytes_to_event_deserializer.py +9 -4
  9. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/implementations/cdc_record_bytes_to_event_serializer.py +6 -1
  10. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/in_memory/in_memory_multiqueue_repository.py +0 -20
  11. {buz-2.13.1rc6 → buz-2.13.1rc8}/LICENSE +0 -0
  12. {buz-2.13.1rc6 → buz-2.13.1rc8}/README.md +0 -0
  13. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/__init__.py +0 -0
  14. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/__init__.py +0 -0
  15. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/__init__.py +0 -0
  16. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/base_command_handler.py +0 -0
  17. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/command_bus.py +0 -0
  18. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/command_handler.py +0 -0
  19. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/__init__.py +0 -0
  20. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/base_handle_middleware.py +0 -0
  21. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/handle_middleware.py +0 -0
  22. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/handle_middleware_chain_resolver.py +0 -0
  23. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/self_process/__init__.py +0 -0
  24. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/self_process/self_process_command_bus.py +0 -0
  25. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/command.py +0 -0
  26. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/more_than_one_command_handler_related_exception.py +0 -0
  27. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/__init__.py +0 -0
  28. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/base_command_handler.py +0 -0
  29. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/command_bus.py +0 -0
  30. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/command_handler.py +0 -0
  31. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/__init__.py +0 -0
  32. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/base_handle_middleware.py +0 -0
  33. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/handle_middleware.py +0 -0
  34. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/handle_middleware_chain_resolver.py +0 -0
  35. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/self_process/__init__.py +0 -0
  36. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/self_process/self_process_command_bus.py +0 -0
  37. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/synced_async/__init__.py +0 -0
  38. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/synced_async/synced_async_command_bus.py +0 -0
  39. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/__init__.py +0 -0
  40. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/async_consumer.py +0 -0
  41. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/async_subscriber.py +0 -0
  42. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/async_worker.py +0 -0
  43. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/base_async_subscriber.py +0 -0
  44. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/base_subscriber.py +0 -0
  45. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/consumer.py +0 -0
  46. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/__init__.py +0 -0
  47. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/dlq_criteria.py +0 -0
  48. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/dlq_repository.py +0 -0
  49. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/event.py +0 -0
  50. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/event_bus.py +0 -0
  51. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/__init__.py +0 -0
  52. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/event_not_published_exception.py +0 -0
  53. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/event_restore_exception.py +0 -0
  54. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/subscribers_not_found_exception.py +0 -0
  55. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/term_signal_interruption_exception.py +0 -0
  56. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/worker_execution_exception.py +0 -0
  57. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/__init__.py +0 -0
  58. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/__init__.py +0 -0
  59. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_aiokafka_async_consumer.py +0 -0
  60. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_aiokafka_multi_threaded_consumer.py +0 -0
  61. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/__init__.py +0 -0
  62. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/consume_strategy.py +0 -0
  63. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/kafka_on_fail_strategy.py +0 -0
  64. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/topic_and_subscription_group_per_subscriber_kafka_consumer_strategy.py +0 -0
  65. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/exceptions/__init__.py +0 -0
  66. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/exceptions/kafka_event_bus_config_not_valid_exception.py +0 -0
  67. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/kafka_event_async_subscriber_executor.py +0 -0
  68. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/kafka_event_subscriber_executor.py +0 -0
  69. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/kafka_event_sync_subscriber_executor.py +0 -0
  70. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/publish_strategy/__init__.py +0 -0
  71. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/publish_strategy/publish_strategy.py +0 -0
  72. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/publish_strategy/topic_per_event_kafka_publish_strategy.py +0 -0
  73. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/__init__.py +0 -0
  74. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/allowed_kombu_serializer.py +0 -0
  75. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/consume_strategy/__init__.py +0 -0
  76. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/consume_strategy/consume_strategy.py +0 -0
  77. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/consume_strategy/queue_per_subscriber_consume_strategy.py +0 -0
  78. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/kombu_consumer.py +0 -0
  79. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/kombu_event_bus.py +0 -0
  80. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/publish_strategy/__init__.py +0 -0
  81. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/publish_strategy/fanout_exchange_per_event_publish_strategy.py +0 -0
  82. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/publish_strategy/publish_strategy.py +0 -0
  83. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/retry_strategy/__init__.py +0 -0
  84. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/retry_strategy/publish_retry_policy.py +0 -0
  85. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/retry_strategy/simple_publish_retry_policy.py +0 -0
  86. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/models/consuming_task.py +0 -0
  87. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/queue/__init__.py +0 -0
  88. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/meta_base_subscriber.py +0 -0
  89. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/meta_subscriber.py +0 -0
  90. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/__init__.py +0 -0
  91. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/async_consume_middleware.py +0 -0
  92. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/async_consume_middleware_chain_resolver.py +0 -0
  93. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/base_consume_middleware.py +0 -0
  94. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/base_publish_middleware.py +0 -0
  95. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/consume_middleware.py +0 -0
  96. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/consume_middleware_chain_resolver.py +0 -0
  97. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/exceptions/__init__.py +0 -0
  98. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/exceptions/event_already_in_progress_exception.py +0 -0
  99. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/publish_middleware.py +0 -0
  100. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/publish_middleware_chain_resolver.py +0 -0
  101. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/__init__.py +0 -0
  102. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/__init__.py +0 -0
  103. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/async_execution_strategy.py +0 -0
  104. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/async_self_process_execution_strategy.py +0 -0
  105. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/cyclic_iterator_execution_strategy.py +0 -0
  106. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/execution_strategy.py +0 -0
  107. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/self_process_execution_strategy.py +0 -0
  108. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/__init__.py +0 -0
  109. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/consume_retrier.py +0 -0
  110. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/consumed_event_retry.py +0 -0
  111. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/consumed_event_retry_repository.py +0 -0
  112. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/max_retries_consume_retrier.py +0 -0
  113. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/max_retries_negative_exception.py +0 -0
  114. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/reject_callback.py +0 -0
  115. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/subscriber.py +0 -0
  116. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/sync/__init__.py +0 -0
  117. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/sync/sync_event_bus.py +0 -0
  118. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/__init__.py +0 -0
  119. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/event_to_outbox_record_translator.py +0 -0
  120. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/fqn_to_event_mapper.py +0 -0
  121. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/__init__.py +0 -0
  122. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/deliverable_records_outbox_criteria_factory.py +0 -0
  123. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/outbox_criteria.py +0 -0
  124. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/outbox_criteria_factory.py +0 -0
  125. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/outbox_sorting_criteria.py +0 -0
  126. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record.py +0 -0
  127. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_finder/__init__.py +0 -0
  128. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_finder/outbox_record_stream_finder.py +0 -0
  129. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_finder/polling_outbox_record_stream_finder.py +0 -0
  130. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_to_event_translator.py +0 -0
  131. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/__init__.py +0 -0
  132. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/abstract_outbox_record_validator.py +0 -0
  133. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/outbox_record_size_not_allowed_exception.py +0 -0
  134. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/outbox_record_validation_exception.py +0 -0
  135. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/outbox_record_validator.py +0 -0
  136. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/size_outbox_record_validator.py +0 -0
  137. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_repository.py +0 -0
  138. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/transactional_outbox_event_bus.py +0 -0
  139. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/transactional_outbox_worker.py +0 -0
  140. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/worker.py +0 -0
  141. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/handler.py +0 -0
  142. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/__init__.py +0 -0
  143. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/exceptions/not_valid_kafka_message_exception.py +0 -0
  144. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/exceptions/topic_already_created_exception.py +0 -0
  145. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/auto_create_topic_configuration.py +0 -0
  146. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/consumer_initial_offset_position.py +0 -0
  147. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/create_kafka_topic.py +0 -0
  148. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_config.py +0 -0
  149. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_credentials.py +0 -0
  150. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_plain_text_credentials.py +0 -0
  151. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_sasl_credentials.py +0 -0
  152. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_consumer_record.py +0 -0
  153. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_poll_record.py +0 -0
  154. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_supported_sasl_mechanisms.py +0 -0
  155. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_supported_security_protocols.py +0 -0
  156. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/services/kafka_admin_client.py +0 -0
  157. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/services/kafka_admin_test_client.py +0 -0
  158. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/services/kafka_producer.py +0 -0
  159. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/__init__.py +0 -0
  160. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/__init__.py +0 -0
  161. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/rebalance/__init__.py +0 -0
  162. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/rebalance/kafka_callback_rebalancer.py +0 -0
  163. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/translators/__init__.py +0 -0
  164. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/translators/consumer_initial_offset_position_translator.py +0 -0
  165. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/__init__.py +0 -0
  166. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/byte_deserializer.py +0 -0
  167. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/bytes_to_message_deserializer.py +0 -0
  168. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/__init__.py +0 -0
  169. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/cdc/not_valid_cdc_message_exception.py +0 -0
  170. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/json_byte_deserializer.py +0 -0
  171. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/json_bytes_to_message_deserializer.py +0 -0
  172. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/__init__.py +0 -0
  173. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/exception/consumer_interrupted_exception.py +0 -0
  174. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/factories/__init__.py +0 -0
  175. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/factories/kafka_python_producer_factory.py +0 -0
  176. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/kafka_python_admin_client.py +0 -0
  177. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/kafka_python_admin_test_client.py +0 -0
  178. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/kafka_python_producer.py +0 -0
  179. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/translators/__init__.py +0 -0
  180. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/translators/consumer_initial_offset_position_translator.py +0 -0
  181. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/byte_serializer.py +0 -0
  182. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/implementations/json_byte_serializer.py +0 -0
  183. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/kafka_header_serializer.py +0 -0
  184. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/__init__.py +0 -0
  185. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/handler_fqn_not_found_exception.py +0 -0
  186. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/locator.py +0 -0
  187. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/message_fqn_not_found_exception.py +0 -0
  188. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/__init__.py +0 -0
  189. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/container_locator.py +0 -0
  190. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/container_locator_resolution_configuration.py +0 -0
  191. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/handler_not_found_exception.py +0 -0
  192. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/handler_not_registered_exception.py +0 -0
  193. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/__init__.py +0 -0
  194. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/handler_already_registered_exception.py +0 -0
  195. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/handler_not_registered_exception.py +0 -0
  196. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/instance_locator.py +0 -0
  197. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/message.py +0 -0
  198. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/middleware/__init__.py +0 -0
  199. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/middleware/middleware.py +0 -0
  200. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/middleware/middleware_chain_builder.py +0 -0
  201. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/py.typed +0 -0
  202. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/__init__.py +0 -0
  203. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/__init__.py +0 -0
  204. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/base_query_handler.py +0 -0
  205. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/__init__.py +0 -0
  206. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/base_handle_middleware.py +0 -0
  207. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/handle_middleware.py +0 -0
  208. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/handle_middleware_chain_resolver.py +0 -0
  209. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/query_bus.py +0 -0
  210. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/query_handler.py +0 -0
  211. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/self_process/__init__.py +0 -0
  212. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/self_process/self_process_query_bus.py +0 -0
  213. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/more_than_one_query_handler_related_exception.py +0 -0
  214. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/query.py +0 -0
  215. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/query_response.py +0 -0
  216. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/__init__.py +0 -0
  217. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/base_query_handler.py +0 -0
  218. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/__init__.py +0 -0
  219. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/base_handle_middleware.py +0 -0
  220. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/handle_middleware.py +0 -0
  221. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/handle_middleware_chain_resolver.py +0 -0
  222. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/query_bus.py +0 -0
  223. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/query_handler.py +0 -0
  224. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/self_process/__init__.py +0 -0
  225. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/self_process/self_process_query_bus.py +0 -0
  226. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/synced_async/__init__.py +0 -0
  227. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/synced_async/synced_async_query_bus.py +0 -0
  228. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/__init__.py +0 -0
  229. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/in_memory/in_memory_queue_repository.py +0 -0
  230. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/multiqueue_repository.py +0 -0
  231. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/queue_repository.py +0 -0
  232. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/serializer/message_to_bytes_serializer.py +0 -0
  233. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/serializer/message_to_json_bytes_serializer.py +0 -0
  234. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/wrapper/__init__.py +0 -0
  235. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/wrapper/async_to_sync.py +0 -0
  236. {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/wrapper/event_loop.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: buz
3
- Version: 2.13.1rc6
3
+ Version: 2.13.1rc8
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "buz"
3
- version = "2.13.1rc6"
3
+ version = "2.13.1rc8"
4
4
  description = "Buz is a set of light, simple and extensible implementations of event, command and query buses."
5
5
  readme = "README.md"
6
6
  authors = ["Luis Pintado Lozano <luis.pintado.lozano@gmail.com>", "Gerardo Parra <gprauxiliar@gmail.com>"]
@@ -37,6 +37,7 @@ black = "^23.3"
37
37
  mypy = "^1.2"
38
38
  flake8 = "^5.0.4"
39
39
  tenacity = "^8.5.0"
40
+ freezegun = "^1.5.1"
40
41
  types-cachetools = "^5.5.0.20240820"
41
42
 
42
43
  [tool.poetry.extras]
@@ -8,6 +8,7 @@ DlqRecordId = UUID
8
8
 
9
9
  @dataclass
10
10
  class DlqRecord:
11
+ __EXCEPTION_MESSAGE_MAX_CHARACTERS: ClassVar[int] = 300
11
12
  DATE_TIME_FORMAT: ClassVar[str] = "%Y-%m-%d %H:%M:%S.%f"
12
13
 
13
14
  id: DlqRecordId
@@ -18,6 +19,18 @@ class DlqRecord:
18
19
  exception_message: str
19
20
  last_failed_at: datetime
20
21
 
22
+ def __post_init__(self) -> None:
23
+ self.exception_message = self.__add_ellipsis(self.exception_message)
24
+
25
+ def __add_ellipsis(self, message: str) -> str:
26
+ if len(message) <= self.__EXCEPTION_MESSAGE_MAX_CHARACTERS:
27
+ return message
28
+ return message[: self.__EXCEPTION_MESSAGE_MAX_CHARACTERS - 3] + "..."
29
+
30
+ def set_exception(self, exception: Exception) -> None:
31
+ self.exception_type = type(exception).__name__
32
+ self.exception_message = self.__add_ellipsis(str(exception))
33
+
21
34
  def mark_as_failed(self) -> None:
22
35
  self.last_failed_at = datetime.now()
23
36
 
@@ -1,5 +1,5 @@
1
- from abc import abstractmethod
2
1
  import traceback
2
+ from abc import abstractmethod
3
3
  from asyncio import Lock, Task, create_task, gather, Semaphore, Event as AsyncIOEvent, sleep
4
4
  from datetime import timedelta, datetime
5
5
  from itertools import cycle
@@ -28,7 +28,6 @@ from buz.kafka.infrastructure.aiokafka.aiokafka_consumer import AIOKafkaConsumer
28
28
  from buz.queue.in_memory.in_memory_multiqueue_repository import InMemoryMultiqueueRepository
29
29
  from buz.queue.multiqueue_repository import MultiqueueRepository
30
30
 
31
-
32
31
  T = TypeVar("T", bound=Event)
33
32
 
34
33
 
@@ -60,7 +59,6 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
60
59
  self._logger = logger
61
60
  self.__consumer_initial_offset_position = consumer_initial_offset_position
62
61
  self.__max_records_retrieved_per_poll = 1
63
- self.__subscriber_per_consumer_mapper: dict[AIOKafkaConsumer, MetaSubscriber] = {}
64
62
  self.__executor_per_consumer_mapper: dict[AIOKafkaConsumer, KafkaEventSubscriberExecutor] = {}
65
63
  self.__queue_per_consumer_mapper: dict[
66
64
  AIOKafkaConsumer, MultiqueueRepository[TopicPartition, KafkaPollRecord]
@@ -88,15 +86,13 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
88
86
  async def run(self) -> None:
89
87
  start_time = datetime.now()
90
88
  await self.__generate_kafka_consumers()
89
+ self.__initial_coroutines_created_elapsed_time = datetime.now() - start_time
91
90
 
92
91
  if len(self.__executor_per_consumer_mapper) == 0:
93
92
  self._logger.error("There are no valid subscribers to execute, finalizing consumer")
94
93
  return
95
94
 
96
- self.__initial_coroutines_created_elapsed_time = datetime.now() - start_time
97
-
98
95
  start_consumption_time = datetime.now()
99
- self._logger.info("Starting to consume events")
100
96
  worker_errors = await self.__run_worker()
101
97
  self.__events_processed_elapsed_time = datetime.now() - start_consumption_time
102
98
 
@@ -112,9 +108,9 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
112
108
  if self.__exceptions_are_thrown(worker_errors):
113
109
  consume_events_exception, polling_task_exception = worker_errors
114
110
  if consume_events_exception:
115
- self._logger.error(consume_events_exception)
111
+ self._logger.exception(consume_events_exception)
116
112
  if polling_task_exception:
117
- self._logger.error(polling_task_exception)
113
+ self._logger.exception(polling_task_exception)
118
114
 
119
115
  raise WorkerExecutionException("The worker was closed by an unexpected exception")
120
116
 
@@ -131,9 +127,9 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
131
127
  polling_task_exception = await self.__await_exception(polling_task)
132
128
  return (consume_events_exception, polling_task_exception)
133
129
 
134
- async def __await_exception(self, future: Task) -> Optional[Exception]:
130
+ async def __await_exception(self, task: Task) -> Optional[Exception]:
135
131
  try:
136
- await future
132
+ await task
137
133
  return None
138
134
  except Exception as exception:
139
135
  return exception
@@ -143,11 +139,11 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
143
139
 
144
140
  async def __generate_kafka_consumers(self):
145
141
  start_time = datetime.now()
146
- tasks = [self.__initialize_kafka_consumer_for_subscriber(subscriber) for subscriber in self.__subscribers]
142
+ tasks = [self.__generate_kafka_consumer_for_subscriber(subscriber) for subscriber in self.__subscribers]
147
143
  await gather(*tasks)
148
144
  self.__start_kafka_consumers_elapsed_time = datetime.now() - start_time
149
145
 
150
- async def __initialize_kafka_consumer_for_subscriber(self, subscriber: MetaSubscriber) -> None:
146
+ async def __generate_kafka_consumer_for_subscriber(self, subscriber: MetaSubscriber) -> None:
151
147
  try:
152
148
  executor = await self._create_kafka_consumer_executor(subscriber)
153
149
  topics = self.__consume_strategy.get_topics(subscriber)
@@ -167,103 +163,92 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
167
163
 
168
164
  self.__queue_per_consumer_mapper[kafka_consumer] = InMemoryMultiqueueRepository()
169
165
 
170
- # The purpose of this block is to initialize the consumer without delay the execution of the polling thread
171
- # If some of the subscribers haven't as many partitions as subscriber they will not be able to be initialized
172
- # (but maybe they should be initialized in the future)
173
- create_task(self.__init_consumer(kafka_consumer, subscriber))
174
166
  except Exception:
175
167
  self._logger.exception(
176
168
  f"Unexpected error during Kafka subscriber '{subscriber.fqn()}' creation. Skipping it: {traceback.format_exc()}"
177
169
  )
178
170
 
179
- async def __init_consumer(self, consumer: AIOKafkaConsumer, subscriber: MetaSubscriber) -> None:
180
- try:
181
- await consumer.init()
182
- self.__subscriber_per_consumer_mapper[consumer] = subscriber
183
- self._logger.info(f"initialized '{subscriber.fqn()}'")
184
- except Exception:
185
- self._logger.exception(
186
- f"Unexpected error during Kafka subscriber '{subscriber.fqn()}' initialization. Skipping it: {traceback.format_exc()}"
187
- )
188
-
189
171
  @abstractmethod
190
172
  async def _create_kafka_consumer_executor(self, subscriber: MetaSubscriber) -> KafkaEventSubscriberExecutor:
191
173
  pass
192
174
 
193
175
  async def __polling_task(self) -> None:
176
+ self._logger.info("Initializing subscribers")
194
177
  try:
195
- while not self.__should_stop.is_set():
196
- total_size = sum([queue.get_total_size() for queue in self.__queue_per_consumer_mapper.values()])
197
- if total_size >= self.__max_queue_size:
198
- await sleep(self.__seconds_between_polls_if_there_are_tasks_in_the_queue)
199
- continue
200
-
201
- raw_consuming_tasks = await gather(
202
- *[
203
- self.__polling_consuming_tasks(kafka_consumer=consumer)
204
- for consumer, subscriber in self.__subscriber_per_consumer_mapper.items()
205
- ]
206
- )
178
+ polling_task_per_consumer = [
179
+ create_task(self.__polling_consuming_tasks(consumer))
180
+ for consumer, subscriber in self.__queue_per_consumer_mapper.items()
181
+ ]
207
182
 
208
- poll_results: list[ConsumingTask] = [
209
- consuming_task for consuming_tasks in raw_consuming_tasks for consuming_task in consuming_tasks
210
- ]
211
- if len(poll_results) == 0:
212
- await sleep(self.__seconds_between_polls_if_there_are_no_new_tasks)
213
-
214
- for poll_result in poll_results:
215
- queue = self.__queue_per_consumer_mapper[poll_result.consumer]
216
- queue.push(
217
- key=TopicPartition(
218
- topic=poll_result.kafka_poll_record.topic, partition=poll_result.kafka_poll_record.partition
219
- ),
220
- record=poll_result.kafka_poll_record,
221
- )
183
+ await gather(*polling_task_per_consumer)
222
184
 
223
185
  except Exception:
224
186
  self._logger.error(f"Polling task failed with exception: {traceback.format_exc()}")
225
187
  self.__should_stop.set()
226
188
 
227
- return
189
+ async def __polling_consuming_tasks(self, consumer: AIOKafkaConsumer) -> None:
190
+ queue = self.__queue_per_consumer_mapper[consumer]
228
191
 
229
- async def __polling_consuming_tasks(self, kafka_consumer: AIOKafkaConsumer) -> list[ConsumingTask]:
230
- async with self.__polling_tasks_semaphore:
231
- results = await kafka_consumer.poll(
232
- number_of_messages_to_poll=self.__max_records_retrieved_per_poll,
192
+ try:
193
+ self._logger.info(
194
+ f"initializing consumer group: '{consumer.get_consumer_group()}' subscribed to the topics: '{consumer.get_topics()}'"
233
195
  )
234
- return [ConsumingTask(kafka_consumer, result) for result in results]
196
+ await consumer.init()
197
+ self._logger.info(f"initialized '{consumer.get_consumer_group()}'")
198
+ except Exception:
199
+ self._logger.exception(
200
+ f"Unexpected error during Kafka subscriber '{consumer.get_consumer_group()}' initialization. Skipping it: {traceback.format_exc()}"
201
+ )
202
+
203
+ while not self.__should_stop.is_set():
204
+ total_size = sum([queue.get_total_size() for queue in self.__queue_per_consumer_mapper.values()])
205
+ if total_size >= self.__max_queue_size:
206
+ await sleep(self.__seconds_between_polls_if_there_are_tasks_in_the_queue)
207
+ continue
208
+
209
+ async with self.__polling_tasks_semaphore:
210
+ kafka_poll_records = await consumer.poll(
211
+ number_of_messages_to_poll=self.__max_records_retrieved_per_poll,
212
+ )
213
+
214
+ for kafka_poll_record in kafka_poll_records:
215
+ queue.push(
216
+ key=TopicPartition(
217
+ topic=kafka_poll_record.topic,
218
+ partition=kafka_poll_record.partition,
219
+ ),
220
+ record=kafka_poll_record,
221
+ )
222
+
223
+ if len(kafka_poll_records) == 0:
224
+ await sleep(self.__seconds_between_polls_if_there_are_no_new_tasks)
235
225
 
236
226
  async def __consume_events_task(self) -> None:
237
- blocked_tasks_iterator = self.generate_blocked_consuming_tasks_iterator()
227
+ self._logger.info("Initializing consuming task")
228
+ blocked_tasks_iterator = self.__generate_blocked_consuming_tasks_iterator()
238
229
 
239
230
  async for consuming_task in blocked_tasks_iterator:
240
231
  consumer = consuming_task.consumer
241
232
  kafka_poll_record = consuming_task.kafka_poll_record
242
- executor = self.__executor_per_consumer_mapper[consuming_task.consumer]
243
233
 
234
+ executor = self.__executor_per_consumer_mapper[consumer]
244
235
  await executor.consume(kafka_poll_record=kafka_poll_record)
245
-
246
236
  await consumer.commit_poll_record(kafka_poll_record)
247
237
 
248
238
  self.__events_processed += 1
249
239
 
250
240
  # This iterator return a blocked task, that will be blocked for other process (like rebalancing), until the next task will be requested
251
- async def generate_blocked_consuming_tasks_iterator(self) -> AsyncIterator[ConsumingTask]:
241
+ async def __generate_blocked_consuming_tasks_iterator(self) -> AsyncIterator[ConsumingTask]:
252
242
  consumer_queues_cyclic_iterator = cycle(self.__queue_per_consumer_mapper.items())
253
243
  last_consumer, _ = next(consumer_queues_cyclic_iterator)
254
244
 
255
245
  while not self.__should_stop.is_set():
256
- all_queues_are_empty = all(
257
- [queue.is_totally_empty() for queue in self.__queue_per_consumer_mapper.values()]
258
- )
259
-
260
- if all_queues_are_empty:
246
+ if await self.__all_queues_are_empty():
261
247
  await sleep(self.__seconds_between_executions_if_there_are_no_tasks_in_the_queue)
262
248
  continue
263
249
 
264
250
  async with self.__task_execution_mutex:
265
251
  consumer: Optional[AIOKafkaConsumer] = None
266
- kafka_poll_record: Optional[KafkaPollRecord] = None
267
252
 
268
253
  while consumer != last_consumer:
269
254
  consumer, queue = next(consumer_queues_cyclic_iterator)
@@ -274,7 +259,8 @@ class BaseBuzAIOKafkaAsyncConsumer(AsyncConsumer):
274
259
  last_consumer = consumer
275
260
  break
276
261
 
277
- return
262
+ async def __all_queues_are_empty(self) -> bool:
263
+ return all([queue.is_totally_empty() for queue in self.__queue_per_consumer_mapper.values()])
278
264
 
279
265
  async def __on_partition_revoked(self, consumer: AIOKafkaConsumer, topics_partitions: set[TopicPartition]) -> None:
280
266
  async with self.__task_execution_mutex:
@@ -14,6 +14,7 @@ from buz.event.middleware.publish_middleware_chain_resolver import PublishMiddle
14
14
  from buz.kafka import (
15
15
  KafkaPythonProducer,
16
16
  )
17
+ from buz.kafka.domain.exceptions.topic_already_created_exception import KafkaTopicsAlreadyCreatedException
17
18
  from buz.kafka.domain.models.auto_create_topic_configuration import AutoCreateTopicConfiguration
18
19
  from buz.kafka.domain.models.create_kafka_topic import CreateKafkaTopic
19
20
  from buz.kafka.domain.services.kafka_admin_client import KafkaAdminClient
@@ -53,18 +54,22 @@ class BuzKafkaEventBus(EventBus):
53
54
  topic = self.__publish_strategy.get_topic(event)
54
55
 
55
56
  if self.__auto_create_topic_configuration is not None and self.__is_topic_created(topic) is False:
56
- self.__get_kafka_admin_client().create_topics(
57
- topics=[
58
- CreateKafkaTopic(
59
- name=topic,
60
- partitions=self.__auto_create_topic_configuration.partitions,
61
- replication_factor=self.__auto_create_topic_configuration.replication_factor,
62
- configs=self.__auto_create_topic_configuration.configs,
63
- )
64
- ]
65
- )
66
- self.__logger.info(f"Created missing topic: {topic}")
67
- self.__topics_checked[topic] = True
57
+ try:
58
+ self.__logger.info(f"Creating missing topic: {topic}..")
59
+ self.__get_kafka_admin_client().create_topics(
60
+ topics=[
61
+ CreateKafkaTopic(
62
+ name=topic,
63
+ partitions=self.__auto_create_topic_configuration.partitions,
64
+ replication_factor=self.__auto_create_topic_configuration.replication_factor,
65
+ configs=self.__auto_create_topic_configuration.configs,
66
+ )
67
+ ]
68
+ )
69
+ self.__logger.info(f"Created missing topic: {topic}")
70
+ self.__topics_checked[topic] = True
71
+ except KafkaTopicsAlreadyCreatedException:
72
+ pass
68
73
 
69
74
  headers = self.__get_event_headers(event)
70
75
  self.__producer.produce(
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from logging import Logger
4
4
  from ssl import SSLContext
5
- from typing import Awaitable, Callable, Optional, cast
5
+ from typing import Awaitable, Callable, Optional, Sequence, cast
6
6
 
7
7
  from aiokafka import AIOKafkaConsumer as AIOKafkaNativeConsumer, TopicPartition, OffsetAndMetadata
8
8
  from aiokafka.helpers import create_ssl_context
@@ -56,6 +56,12 @@ class AIOKafkaConsumer:
56
56
  self.__check_kafka_admin_client_is_needed()
57
57
  self.__consumer = self.__generate_consumer()
58
58
 
59
+ def get_topics(self) -> Sequence[str]:
60
+ return list(self.__topics)
61
+
62
+ def get_consumer_group(self) -> str:
63
+ return self.__consumer_group
64
+
59
65
  def __check_kafka_admin_client_is_needed(self) -> None:
60
66
  if self.__kafka_admin_client is None and self.__auto_create_topic_configuration is not None:
61
67
  raise KafkaEventBusConfigNotValidException(
@@ -117,7 +123,7 @@ class AIOKafkaConsumer:
117
123
  try:
118
124
  self.__logger.info(f"Creating missing topics: {non_created_topics}...")
119
125
  kafka_admin_client.create_topics(topics=topics_to_create)
120
- self.__logger.info(f"Created missing topics: {non_created_topics}...")
126
+ self.__logger.info(f"Created missing topics: {non_created_topics}")
121
127
  except KafkaTopicsAlreadyCreatedException:
122
128
  # there is a possibility to have a race condition between the check and the creation
123
129
  # but it does not matters, the important part is that the topic is created
@@ -3,9 +3,11 @@ from dataclasses import dataclass
3
3
 
4
4
  @dataclass(frozen=True)
5
5
  class CDCPayload:
6
+ DATE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
7
+
6
8
  payload: str # json encoded
7
9
  event_id: str # uuid
8
- created_at: str # date and hour ISO 8601
10
+ created_at: str
9
11
  event_fqn: str
10
12
 
11
13
  def validate(self) -> None:
@@ -1,16 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from datetime import datetime
3
4
  from typing import TypeVar, Type, Generic
4
5
 
5
6
  import orjson
6
7
  from dacite import from_dict
7
8
 
8
- from buz.kafka.infrastructure.deserializers.implementations.cdc.not_valid_cdc_message_exception import (
9
- NotValidCDCMessageException,
10
- )
11
9
  from buz.event import Event
12
10
  from buz.kafka.infrastructure.cdc.cdc_message import CDCMessage, CDCPayload
13
11
  from buz.kafka.infrastructure.deserializers.bytes_to_message_deserializer import BytesToMessageDeserializer
12
+ from buz.kafka.infrastructure.deserializers.implementations.cdc.not_valid_cdc_message_exception import (
13
+ NotValidCDCMessageException,
14
+ )
14
15
 
15
16
  T = TypeVar("T", bound=Event)
16
17
 
@@ -27,12 +28,16 @@ class CDCRecordBytesToEventDeserializer(BytesToMessageDeserializer[Event], Gener
27
28
  cdc_message = self.__get_outbox_record_as_dict(decoded_string)
28
29
  return self.__event_class.restore(
29
30
  id=cdc_message.payload.event_id,
30
- created_at=cdc_message.payload.created_at,
31
+ created_at=self.__get_created_at_in_event_format(cdc_message.payload.created_at),
31
32
  **orjson.loads(cdc_message.payload.payload),
32
33
  )
33
34
  except Exception as exception:
34
35
  raise NotValidCDCMessageException(decoded_string, exception) from exception
35
36
 
37
+ def __get_created_at_in_event_format(self, cdc_payload_created_at: str) -> str:
38
+ created_at_datetime = datetime.strptime(cdc_payload_created_at, CDCPayload.DATE_TIME_FORMAT)
39
+ return created_at_datetime.strftime(Event.DATE_TIME_FORMAT)
40
+
36
41
  def __get_outbox_record_as_dict(self, decoded_string: str) -> CDCMessage:
37
42
  decoded_record: dict = orjson.loads(decoded_string)
38
43
 
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import asdict
4
+ from datetime import datetime
4
5
 
5
6
  from buz.event import Event
6
7
  from buz.kafka.infrastructure.cdc.cdc_message import CDCMessage, CDCPayload
@@ -16,13 +17,17 @@ class CDCRecordBytesToEventSerializer(ByteSerializer):
16
17
  cdc_message: CDCMessage = CDCMessage(
17
18
  payload=CDCPayload(
18
19
  event_id=data.id,
19
- created_at=data.created_at,
20
+ created_at=self.__adapt_created_to_cdc_format(data.created_at),
20
21
  event_fqn=data.fqn(),
21
22
  payload=self.__serialize_payload(data),
22
23
  )
23
24
  )
24
25
  return self.__json_serializer.serialize(asdict(cdc_message))
25
26
 
27
+ def __adapt_created_to_cdc_format(self, created_at: str) -> str:
28
+ created_at_datetime = datetime.strptime(created_at, Event.DATE_TIME_FORMAT)
29
+ return created_at_datetime.strftime(CDCPayload.DATE_TIME_FORMAT)
30
+
26
31
  def __serialize_payload(self, event: Event) -> str:
27
32
  # Remove id and created at, because Transactional outbox is not adding them
28
33
  payload = asdict(event)
@@ -1,37 +1,20 @@
1
- from threading import Lock
2
1
  from queue import Queue, Empty
3
2
  from typing import Optional, TypeVar, cast
4
3
 
5
4
  from buz.queue.multiqueue_repository import MultiqueueRepository
6
5
 
7
-
8
6
  K = TypeVar("K")
9
7
  R = TypeVar("R")
10
8
 
11
9
 
12
- def self_mutex(method):
13
- def call(self, *args, **kwargs):
14
- lock: Lock = self._get_method_lock() # type: ignore
15
- with lock:
16
- return method(self, *args, **kwargs)
17
-
18
- return call
19
-
20
-
21
10
  class InMemoryMultiqueueRepository(MultiqueueRepository[K, R]):
22
11
  def __init__(self):
23
12
  self.__queues = cast(dict[K, Queue[R]], {})
24
- self.__mutex = Lock()
25
13
  self.__last_key_index = 0
26
14
 
27
- def _get_method_lock(self) -> Lock:
28
- return self.__mutex
29
-
30
- @self_mutex
31
15
  def clear(self, key: K) -> None:
32
16
  self.__queues.pop(key, None)
33
17
 
34
- @self_mutex
35
18
  def push(self, key: K, record: R) -> None:
36
19
  if key not in self.__queues:
37
20
  self.__add_key(key)
@@ -41,7 +24,6 @@ class InMemoryMultiqueueRepository(MultiqueueRepository[K, R]):
41
24
  def __add_key(self, key: K) -> None:
42
25
  self.__queues[key] = Queue[R]()
43
26
 
44
- @self_mutex
45
27
  def pop(self) -> Optional[R]:
46
28
  if not self.__queues:
47
29
  return None
@@ -65,10 +47,8 @@ class InMemoryMultiqueueRepository(MultiqueueRepository[K, R]):
65
47
 
66
48
  return None
67
49
 
68
- @self_mutex
69
50
  def get_total_size(self) -> int:
70
51
  return sum([queue.qsize() for queue in self.__queues.values()])
71
52
 
72
- @self_mutex
73
53
  def is_totally_empty(self) -> bool:
74
54
  return all([queue.empty() for queue in self.__queues.values()])
File without changes
File without changes
File without changes
File without changes