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.
- {buz-2.13.1rc6 → buz-2.13.1rc8}/PKG-INFO +1 -1
- {buz-2.13.1rc6 → buz-2.13.1rc8}/pyproject.toml +2 -1
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/dlq_record.py +13 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/base_buz_aiokafka_async_consumer.py +55 -69
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_kafka_event_bus.py +17 -12
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/aiokafka_consumer.py +8 -2
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/cdc/cdc_message.py +3 -1
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/cdc/cdc_record_bytes_to_event_deserializer.py +9 -4
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/implementations/cdc_record_bytes_to_event_serializer.py +6 -1
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/in_memory/in_memory_multiqueue_repository.py +0 -20
- {buz-2.13.1rc6 → buz-2.13.1rc8}/LICENSE +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/README.md +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/base_command_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/command_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/command_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/base_handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/handle_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/self_process/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/self_process/self_process_command_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/command.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/more_than_one_command_handler_related_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/base_command_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/command_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/command_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/base_handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/handle_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/self_process/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/self_process/self_process_command_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/synced_async/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/synced_async/synced_async_command_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/async_consumer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/async_subscriber.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/async_worker.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/base_async_subscriber.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/base_subscriber.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/consumer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/dlq_criteria.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/dead_letter_queue/dlq_repository.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/event.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/event_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/event_not_published_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/event_restore_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/subscribers_not_found_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/term_signal_interruption_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/worker_execution_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_aiokafka_async_consumer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_aiokafka_multi_threaded_consumer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/consume_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/kafka_on_fail_strategy.py +0 -0
- {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
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/exceptions/__init__.py +0 -0
- {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
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/kafka_event_async_subscriber_executor.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/kafka_event_subscriber_executor.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/kafka_event_sync_subscriber_executor.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/publish_strategy/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/publish_strategy/publish_strategy.py +0 -0
- {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
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/allowed_kombu_serializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/consume_strategy/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/consume_strategy/consume_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/consume_strategy/queue_per_subscriber_consume_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/kombu_consumer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/kombu_event_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/publish_strategy/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/publish_strategy/fanout_exchange_per_event_publish_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/publish_strategy/publish_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/retry_strategy/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/retry_strategy/publish_retry_policy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/kombu/retry_strategy/simple_publish_retry_policy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/models/consuming_task.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/queue/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/meta_base_subscriber.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/meta_subscriber.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/async_consume_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/async_consume_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/base_consume_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/base_publish_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/consume_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/consume_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/exceptions/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/exceptions/event_already_in_progress_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/publish_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/middleware/publish_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/async_execution_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/async_self_process_execution_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/cyclic_iterator_execution_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/execution_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/execution_strategy/self_process_execution_strategy.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/consume_retrier.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/consumed_event_retry.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/consumed_event_retry_repository.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/max_retries_consume_retrier.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/max_retries_negative_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/strategies/retry/reject_callback.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/subscriber.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/sync/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/sync/sync_event_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/event_to_outbox_record_translator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/fqn_to_event_mapper.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/deliverable_records_outbox_criteria_factory.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/outbox_criteria.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/outbox_criteria_factory.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_criteria/outbox_sorting_criteria.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_finder/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_finder/outbox_record_stream_finder.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_finder/polling_outbox_record_stream_finder.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_to_event_translator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/abstract_outbox_record_validator.py +0 -0
- {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
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/outbox_record_validation_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/outbox_record_validator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_record_validation/size_outbox_record_validator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/outbox_repository.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/transactional_outbox_event_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/transactional_outbox/transactional_outbox_worker.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/worker.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/exceptions/not_valid_kafka_message_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/exceptions/topic_already_created_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/auto_create_topic_configuration.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/consumer_initial_offset_position.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/create_kafka_topic.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_config.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_credentials.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_plain_text_credentials.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_connection_sasl_credentials.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_consumer_record.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_poll_record.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_supported_sasl_mechanisms.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/models/kafka_supported_security_protocols.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/services/kafka_admin_client.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/services/kafka_admin_test_client.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/domain/services/kafka_producer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/rebalance/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/rebalance/kafka_callback_rebalancer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/translators/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/aiokafka/translators/consumer_initial_offset_position_translator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/byte_deserializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/bytes_to_message_deserializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/cdc/not_valid_cdc_message_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/json_byte_deserializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/deserializers/implementations/json_bytes_to_message_deserializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/exception/consumer_interrupted_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/factories/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/factories/kafka_python_producer_factory.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/kafka_python_admin_client.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/kafka_python_admin_test_client.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/kafka_python_producer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/translators/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/kafka_python/translators/consumer_initial_offset_position_translator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/byte_serializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/implementations/json_byte_serializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/kafka/infrastructure/serializers/kafka_header_serializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/handler_fqn_not_found_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/locator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/message_fqn_not_found_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/container_locator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/container_locator_resolution_configuration.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/handler_not_found_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/pypendency/handler_not_registered_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/handler_already_registered_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/handler_not_registered_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/locator/sync/instance_locator.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/message.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/middleware/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/middleware/middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/middleware/middleware_chain_builder.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/py.typed +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/base_query_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/base_handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/middleware/handle_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/query_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/query_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/self_process/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/asynchronous/self_process/self_process_query_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/more_than_one_query_handler_related_exception.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/query.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/query_response.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/base_query_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/base_handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/handle_middleware.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/middleware/handle_middleware_chain_resolver.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/query_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/query_handler.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/self_process/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/self_process/self_process_query_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/synced_async/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/query/synchronous/synced_async/synced_async_query_bus.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/in_memory/in_memory_queue_repository.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/multiqueue_repository.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/queue/queue_repository.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/serializer/message_to_bytes_serializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/serializer/message_to_json_bytes_serializer.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/wrapper/__init__.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/wrapper/async_to_sync.py +0 -0
- {buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/wrapper/event_loop.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "buz"
|
|
3
|
-
version = "2.13.
|
|
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.
|
|
111
|
+
self._logger.exception(consume_events_exception)
|
|
116
112
|
if polling_task_exception:
|
|
117
|
-
self._logger.
|
|
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,
|
|
130
|
+
async def __await_exception(self, task: Task) -> Optional[Exception]:
|
|
135
131
|
try:
|
|
136
|
-
await
|
|
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.
|
|
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
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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
|
-
|
|
189
|
+
async def __polling_consuming_tasks(self, consumer: AIOKafkaConsumer) -> None:
|
|
190
|
+
queue = self.__queue_per_consumer_mapper[consumer]
|
|
228
191
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/buz_kafka_event_bus.py
RENAMED
|
@@ -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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/base_handle_middleware.py
RENAMED
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/asynchronous/middleware/handle_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/more_than_one_command_handler_related_exception.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/middleware/base_handle_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/self_process/self_process_command_bus.py
RENAMED
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/command/synchronous/synced_async/synced_async_command_bus.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/exceptions/term_signal_interruption_exception.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/consume_strategy/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buz-2.13.1rc6 → buz-2.13.1rc8}/src/buz/event/infrastructure/buz_kafka/exceptions/__init__.py
RENAMED
|
File without changes
|