omnibase_infra 0.2.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnibase_infra/__init__.py +101 -0
- omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
- omnibase_infra/capabilities/__init__.py +15 -0
- omnibase_infra/capabilities/capability_inference_rules.py +211 -0
- omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
- omnibase_infra/capabilities/intent_type_extractor.py +160 -0
- omnibase_infra/cli/__init__.py +1 -0
- omnibase_infra/cli/commands.py +216 -0
- omnibase_infra/clients/__init__.py +0 -0
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/constants_topic_patterns.py +26 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +264 -0
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +141 -0
- omnibase_infra/decorators/__init__.py +29 -0
- omnibase_infra/decorators/allow_any.py +109 -0
- omnibase_infra/dlq/__init__.py +90 -0
- omnibase_infra/dlq/constants_dlq.py +57 -0
- omnibase_infra/dlq/models/__init__.py +26 -0
- omnibase_infra/dlq/models/enum_replay_status.py +37 -0
- omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
- omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
- omnibase_infra/dlq/service_dlq_tracking.py +611 -0
- omnibase_infra/enums/__init__.py +132 -0
- omnibase_infra/enums/enum_any_type_violation.py +104 -0
- omnibase_infra/enums/enum_backend_type.py +27 -0
- omnibase_infra/enums/enum_capture_outcome.py +42 -0
- omnibase_infra/enums/enum_capture_state.py +88 -0
- omnibase_infra/enums/enum_chain_violation_type.py +119 -0
- omnibase_infra/enums/enum_circuit_state.py +51 -0
- omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
- omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
- omnibase_infra/enums/enum_contract_type.py +84 -0
- omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
- omnibase_infra/enums/enum_dispatch_status.py +191 -0
- omnibase_infra/enums/enum_environment.py +46 -0
- omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
- omnibase_infra/enums/enum_handler_error_type.py +111 -0
- omnibase_infra/enums/enum_handler_loader_error.py +178 -0
- omnibase_infra/enums/enum_handler_source_mode.py +86 -0
- omnibase_infra/enums/enum_handler_source_type.py +87 -0
- omnibase_infra/enums/enum_handler_type.py +77 -0
- omnibase_infra/enums/enum_handler_type_category.py +61 -0
- omnibase_infra/enums/enum_infra_transport_type.py +73 -0
- omnibase_infra/enums/enum_introspection_reason.py +154 -0
- omnibase_infra/enums/enum_kafka_acks.py +99 -0
- omnibase_infra/enums/enum_message_category.py +213 -0
- omnibase_infra/enums/enum_node_archetype.py +74 -0
- omnibase_infra/enums/enum_node_output_type.py +185 -0
- omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
- omnibase_infra/enums/enum_policy_type.py +32 -0
- omnibase_infra/enums/enum_registration_state.py +261 -0
- omnibase_infra/enums/enum_registration_status.py +33 -0
- omnibase_infra/enums/enum_registry_response_status.py +28 -0
- omnibase_infra/enums/enum_response_status.py +26 -0
- omnibase_infra/enums/enum_retry_error_category.py +98 -0
- omnibase_infra/enums/enum_security_rule_id.py +103 -0
- omnibase_infra/enums/enum_selection_strategy.py +91 -0
- omnibase_infra/enums/enum_topic_standard.py +42 -0
- omnibase_infra/enums/enum_validation_severity.py +78 -0
- omnibase_infra/errors/__init__.py +160 -0
- omnibase_infra/errors/error_architecture_violation.py +152 -0
- omnibase_infra/errors/error_binding_resolution.py +128 -0
- omnibase_infra/errors/error_chain_propagation.py +188 -0
- omnibase_infra/errors/error_compute_registry.py +95 -0
- omnibase_infra/errors/error_consul.py +132 -0
- omnibase_infra/errors/error_container_wiring.py +243 -0
- omnibase_infra/errors/error_event_bus_registry.py +105 -0
- omnibase_infra/errors/error_infra.py +610 -0
- omnibase_infra/errors/error_message_type_registry.py +101 -0
- omnibase_infra/errors/error_policy_registry.py +115 -0
- omnibase_infra/errors/error_vault.py +123 -0
- omnibase_infra/event_bus/__init__.py +72 -0
- omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +84 -0
- omnibase_infra/event_bus/event_bus_inmemory.py +797 -0
- omnibase_infra/event_bus/event_bus_kafka.py +1716 -0
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +180 -0
- omnibase_infra/event_bus/mixin_kafka_dlq.py +771 -0
- omnibase_infra/event_bus/models/__init__.py +29 -0
- omnibase_infra/event_bus/models/config/__init__.py +20 -0
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +693 -0
- omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
- omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
- omnibase_infra/event_bus/models/model_event_headers.py +115 -0
- omnibase_infra/event_bus/models/model_event_message.py +60 -0
- omnibase_infra/event_bus/testing/__init__.py +26 -0
- omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
- omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
- omnibase_infra/event_bus/topic_constants.py +376 -0
- omnibase_infra/handlers/__init__.py +82 -0
- omnibase_infra/handlers/filesystem/__init__.py +48 -0
- omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
- omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
- omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
- omnibase_infra/handlers/handler_consul.py +795 -0
- omnibase_infra/handlers/handler_db.py +1046 -0
- omnibase_infra/handlers/handler_filesystem.py +1478 -0
- omnibase_infra/handlers/handler_graph.py +2015 -0
- omnibase_infra/handlers/handler_http.py +926 -0
- omnibase_infra/handlers/handler_intent.py +387 -0
- omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
- omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
- omnibase_infra/handlers/handler_mcp.py +1430 -0
- omnibase_infra/handlers/handler_qdrant.py +1076 -0
- omnibase_infra/handlers/handler_vault.py +428 -0
- omnibase_infra/handlers/mcp/__init__.py +19 -0
- omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
- omnibase_infra/handlers/mcp/protocols.py +178 -0
- omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
- omnibase_infra/handlers/mixins/__init__.py +47 -0
- omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +338 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +542 -0
- omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
- omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
- omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
- omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
- omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
- omnibase_infra/handlers/models/__init__.py +286 -0
- omnibase_infra/handlers/models/consul/__init__.py +81 -0
- omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
- omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
- omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
- omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
- omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
- omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
- omnibase_infra/handlers/models/graph/__init__.py +35 -0
- omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
- omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
- omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
- omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
- omnibase_infra/handlers/models/http/__init__.py +50 -0
- omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
- omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
- omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
- omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
- omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
- omnibase_infra/handlers/models/mcp/__init__.py +23 -0
- omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
- omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
- omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
- omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
- omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
- omnibase_infra/handlers/models/model_db_query_response.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
- omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
- omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
- omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
- omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
- omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
- omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
- omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_handler_response.py +103 -0
- omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
- omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
- omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
- omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
- omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
- omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
- omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
- omnibase_infra/handlers/models/model_operation_context.py +187 -0
- omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_retry_state.py +162 -0
- omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
- omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
- omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
- omnibase_infra/handlers/models/vault/__init__.py +69 -0
- omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
- omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
- omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
- omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
- omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
- omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
- omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
- omnibase_infra/handlers/registration_storage/__init__.py +43 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +922 -0
- omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
- omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
- omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
- omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
- omnibase_infra/handlers/service_discovery/__init__.py +43 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +1051 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
- omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
- omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
- omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +109 -0
- omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
- omnibase_infra/idempotency/__init__.py +94 -0
- omnibase_infra/idempotency/models/__init__.py +43 -0
- omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
- omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
- omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
- omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
- omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
- omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
- omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
- omnibase_infra/idempotency/store_inmemory.py +265 -0
- omnibase_infra/idempotency/store_postgres.py +923 -0
- omnibase_infra/infrastructure/__init__.py +0 -0
- omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
- omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
- omnibase_infra/mixins/__init__.py +71 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +656 -0
- omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
- omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
- omnibase_infra/mixins/mixin_node_introspection.py +2670 -0
- omnibase_infra/mixins/mixin_retry_execution.py +386 -0
- omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
- omnibase_infra/models/__init__.py +144 -0
- omnibase_infra/models/bindings/__init__.py +59 -0
- omnibase_infra/models/bindings/constants.py +144 -0
- omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
- omnibase_infra/models/bindings/model_operation_binding.py +44 -0
- omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
- omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
- omnibase_infra/models/corpus/__init__.py +17 -0
- omnibase_infra/models/corpus/model_capture_config.py +133 -0
- omnibase_infra/models/corpus/model_capture_result.py +86 -0
- omnibase_infra/models/discovery/__init__.py +42 -0
- omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
- omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
- omnibase_infra/models/discovery/model_introspection_config.py +330 -0
- omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
- omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
- omnibase_infra/models/dispatch/__init__.py +155 -0
- omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
- omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
- omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
- omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
- omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
- omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
- omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
- omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
- omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
- omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
- omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
- omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
- omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
- omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
- omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
- omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
- omnibase_infra/models/errors/__init__.py +45 -0
- omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
- omnibase_infra/models/errors/model_infra_error_context.py +99 -0
- omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
- omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
- omnibase_infra/models/handlers/__init__.py +80 -0
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +82 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +200 -0
- omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
- omnibase_infra/models/health/__init__.py +9 -0
- omnibase_infra/models/health/model_health_check_result.py +40 -0
- omnibase_infra/models/lifecycle/__init__.py +39 -0
- omnibase_infra/models/logging/__init__.py +51 -0
- omnibase_infra/models/logging/model_log_context.py +756 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/model_node_identity.py +126 -0
- omnibase_infra/models/model_retry_error_classification.py +78 -0
- omnibase_infra/models/projection/__init__.py +43 -0
- omnibase_infra/models/projection/model_capability_fields.py +112 -0
- omnibase_infra/models/projection/model_registration_projection.py +434 -0
- omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
- omnibase_infra/models/projection/model_sequence_info.py +182 -0
- omnibase_infra/models/projection/model_snapshot_topic_config.py +591 -0
- omnibase_infra/models/projectors/__init__.py +41 -0
- omnibase_infra/models/projectors/model_projector_column.py +289 -0
- omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
- omnibase_infra/models/projectors/model_projector_index.py +270 -0
- omnibase_infra/models/projectors/model_projector_schema.py +415 -0
- omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
- omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
- omnibase_infra/models/registration/__init__.py +68 -0
- omnibase_infra/models/registration/commands/__init__.py +15 -0
- omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
- omnibase_infra/models/registration/events/__init__.py +56 -0
- omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
- omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
- omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
- omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
- omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
- omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
- omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
- omnibase_infra/models/registration/model_node_capabilities.py +190 -0
- omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
- omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +195 -0
- omnibase_infra/models/registration/model_node_metadata.py +79 -0
- omnibase_infra/models/registration/model_node_registration.py +162 -0
- omnibase_infra/models/registration/model_node_registration_record.py +162 -0
- omnibase_infra/models/registry/__init__.py +29 -0
- omnibase_infra/models/registry/model_domain_constraint.py +202 -0
- omnibase_infra/models/registry/model_message_type_entry.py +271 -0
- omnibase_infra/models/resilience/__init__.py +9 -0
- omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
- omnibase_infra/models/routing/__init__.py +25 -0
- omnibase_infra/models/routing/model_routing_entry.py +52 -0
- omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
- omnibase_infra/models/runtime/__init__.py +49 -0
- omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
- omnibase_infra/models/runtime/model_discovery_error.py +81 -0
- omnibase_infra/models/runtime/model_discovery_result.py +162 -0
- omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
- omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
- omnibase_infra/models/runtime/model_handler_contract.py +296 -0
- omnibase_infra/models/runtime/model_loaded_handler.py +129 -0
- omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
- omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
- omnibase_infra/models/security/__init__.py +50 -0
- omnibase_infra/models/security/classification_levels.py +99 -0
- omnibase_infra/models/security/model_environment_policy.py +145 -0
- omnibase_infra/models/security/model_handler_security_policy.py +107 -0
- omnibase_infra/models/security/model_security_error.py +81 -0
- omnibase_infra/models/security/model_security_validation_result.py +328 -0
- omnibase_infra/models/security/model_security_warning.py +67 -0
- omnibase_infra/models/snapshot/__init__.py +27 -0
- omnibase_infra/models/snapshot/model_field_change.py +65 -0
- omnibase_infra/models/snapshot/model_snapshot.py +270 -0
- omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
- omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
- omnibase_infra/models/types/__init__.py +71 -0
- omnibase_infra/models/validation/__init__.py +89 -0
- omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
- omnibase_infra/models/validation/model_any_type_violation.py +141 -0
- omnibase_infra/models/validation/model_category_match_result.py +345 -0
- omnibase_infra/models/validation/model_chain_violation.py +166 -0
- omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
- omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
- omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
- omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
- omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
- omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
- omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
- omnibase_infra/models/validation/model_output_validation_params.py +74 -0
- omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
- omnibase_infra/models/validation/model_validation_error_params.py +84 -0
- omnibase_infra/models/validation/model_validation_outcome.py +287 -0
- omnibase_infra/nodes/__init__.py +57 -0
- omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
- omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +203 -0
- omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
- omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
- omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
- omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
- omnibase_infra/nodes/architecture_validator/node.py +262 -0
- omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
- omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
- omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
- omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +106 -0
- omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
- omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
- omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
- omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
- omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
- omnibase_infra/nodes/effects/README.md +358 -0
- omnibase_infra/nodes/effects/__init__.py +26 -0
- omnibase_infra/nodes/effects/contract.yaml +167 -0
- omnibase_infra/nodes/effects/models/__init__.py +32 -0
- omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
- omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
- omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
- omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
- omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
- omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
- omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
- omnibase_infra/nodes/effects/registry_effect.py +525 -0
- omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
- omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
- omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
- omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
- omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
- omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
- omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
- omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
- omnibase_infra/nodes/node_intent_storage_effect/__init__.py +50 -0
- omnibase_infra/nodes/node_intent_storage_effect/contract.yaml +194 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/__init__.py +24 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_input.py +141 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_output.py +130 -0
- omnibase_infra/nodes/node_intent_storage_effect/node.py +94 -0
- omnibase_infra/nodes/node_intent_storage_effect/registry/__init__.py +35 -0
- omnibase_infra/nodes/node_intent_storage_effect/registry/registry_infra_intent_storage.py +294 -0
- omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
- omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
- omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
- omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
- omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
- omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
- omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
- omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +482 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +694 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
- omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
- omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +528 -0
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +393 -0
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +743 -0
- omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
- omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
- omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
- omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
- omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
- omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +220 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
- omnibase_infra/nodes/node_registration_storage_effect/node.py +112 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +215 -0
- omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
- omnibase_infra/nodes/node_registry_effect/contract.yaml +677 -0
- omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +417 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
- omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
- omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
- omnibase_infra/nodes/node_registry_effect/node.py +165 -0
- omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
- omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
- omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +222 -0
- omnibase_infra/nodes/reducers/__init__.py +30 -0
- omnibase_infra/nodes/reducers/models/__init__.py +37 -0
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +87 -0
- omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
- omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
- omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
- omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
- omnibase_infra/nodes/reducers/registration_reducer.py +1138 -0
- omnibase_infra/observability/__init__.py +143 -0
- omnibase_infra/observability/constants_metrics.py +91 -0
- omnibase_infra/observability/factory_observability_sink.py +525 -0
- omnibase_infra/observability/handlers/__init__.py +118 -0
- omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
- omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
- omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
- omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
- omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
- omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
- omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
- omnibase_infra/observability/hooks/__init__.py +74 -0
- omnibase_infra/observability/hooks/hook_observability.py +1223 -0
- omnibase_infra/observability/models/__init__.py +30 -0
- omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
- omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
- omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
- omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
- omnibase_infra/observability/sinks/__init__.py +69 -0
- omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
- omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
- omnibase_infra/plugins/__init__.py +27 -0
- omnibase_infra/plugins/examples/__init__.py +28 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
- omnibase_infra/plugins/models/__init__.py +21 -0
- omnibase_infra/plugins/models/model_plugin_context.py +76 -0
- omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
- omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
- omnibase_infra/plugins/plugin_compute_base.py +449 -0
- omnibase_infra/projectors/__init__.py +30 -0
- omnibase_infra/projectors/contracts/__init__.py +63 -0
- omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
- omnibase_infra/projectors/projection_reader_registration.py +1559 -0
- omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
- omnibase_infra/protocols/__init__.py +104 -0
- omnibase_infra/protocols/protocol_capability_projection.py +253 -0
- omnibase_infra/protocols/protocol_capability_query.py +251 -0
- omnibase_infra/protocols/protocol_container_aware.py +200 -0
- omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
- omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
- omnibase_infra/protocols/protocol_event_projector.py +96 -0
- omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
- omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
- omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
- omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
- omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
- omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
- omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
- omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
- omnibase_infra/runtime/__init__.py +445 -0
- omnibase_infra/runtime/binding_config_resolver.py +2771 -0
- omnibase_infra/runtime/binding_resolver.py +753 -0
- omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/constants_security.py +70 -0
- omnibase_infra/runtime/contract_handler_discovery.py +587 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +51 -0
- omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
- omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
- omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
- omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
- omnibase_infra/runtime/emit_daemon/cli.py +844 -0
- omnibase_infra/runtime/emit_daemon/client.py +811 -0
- omnibase_infra/runtime/emit_daemon/config.py +535 -0
- omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
- omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
- omnibase_infra/runtime/emit_daemon/queue.py +618 -0
- omnibase_infra/runtime/enums/__init__.py +18 -0
- omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
- omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
- omnibase_infra/runtime/envelope_validator.py +179 -0
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
- omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +750 -0
- omnibase_infra/runtime/handler_identity.py +81 -0
- omnibase_infra/runtime/handler_plugin_loader.py +2046 -0
- omnibase_infra/runtime/handler_registry.py +329 -0
- omnibase_infra/runtime/handler_source_resolver.py +367 -0
- omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
- omnibase_infra/runtime/kafka_contract_source.py +984 -0
- omnibase_infra/runtime/kernel.py +40 -0
- omnibase_infra/runtime/mixin_policy_validation.py +522 -0
- omnibase_infra/runtime/mixin_semver_cache.py +402 -0
- omnibase_infra/runtime/mixins/__init__.py +24 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +778 -0
- omnibase_infra/runtime/models/__init__.py +229 -0
- omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
- omnibase_infra/runtime/models/model_binding_config.py +168 -0
- omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
- omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
- omnibase_infra/runtime/models/model_cached_secret.py +138 -0
- omnibase_infra/runtime/models/model_compute_key.py +138 -0
- omnibase_infra/runtime/models/model_compute_registration.py +97 -0
- omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
- omnibase_infra/runtime/models/model_config_ref.py +331 -0
- omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
- omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
- omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
- omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
- omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
- omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
- omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
- omnibase_infra/runtime/models/model_failed_component.py +55 -0
- omnibase_infra/runtime/models/model_health_check_response.py +168 -0
- omnibase_infra/runtime/models/model_health_check_result.py +229 -0
- omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
- omnibase_infra/runtime/models/model_logging_config.py +42 -0
- omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
- omnibase_infra/runtime/models/model_optional_string.py +94 -0
- omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
- omnibase_infra/runtime/models/model_policy_context.py +100 -0
- omnibase_infra/runtime/models/model_policy_key.py +138 -0
- omnibase_infra/runtime/models/model_policy_registration.py +139 -0
- omnibase_infra/runtime/models/model_policy_result.py +103 -0
- omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
- omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
- omnibase_infra/runtime/models/model_retry_policy.py +105 -0
- omnibase_infra/runtime/models/model_runtime_config.py +150 -0
- omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_config.py +625 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
- omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
- omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
- omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
- omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
- omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
- omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
- omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
- omnibase_infra/runtime/models/model_security_config.py +109 -0
- omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
- omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
- omnibase_infra/runtime/projector_schema_manager.py +565 -0
- omnibase_infra/runtime/projector_shell.py +1330 -0
- omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
- omnibase_infra/runtime/protocol_contract_source.py +92 -0
- omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
- omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
- omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
- omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
- omnibase_infra/runtime/protocol_policy.py +366 -0
- omnibase_infra/runtime/protocols/__init__.py +37 -0
- omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
- omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
- omnibase_infra/runtime/registry/__init__.py +93 -0
- omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
- omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
- omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
- omnibase_infra/runtime/registry/registry_message_type.py +542 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +445 -0
- omnibase_infra/runtime/registry_compute.py +1143 -0
- omnibase_infra/runtime/registry_contract_source.py +693 -0
- omnibase_infra/runtime/registry_dispatcher.py +678 -0
- omnibase_infra/runtime/registry_policy.py +1185 -0
- omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
- omnibase_infra/runtime/runtime_scheduler.py +1070 -0
- omnibase_infra/runtime/secret_resolver.py +2112 -0
- omnibase_infra/runtime/security_metadata_validator.py +776 -0
- omnibase_infra/runtime/service_kernel.py +1651 -0
- omnibase_infra/runtime/service_message_dispatch_engine.py +2350 -0
- omnibase_infra/runtime/service_runtime_host_process.py +3493 -0
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +765 -0
- omnibase_infra/runtime/util_container_wiring.py +1124 -0
- omnibase_infra/runtime/util_validation.py +314 -0
- omnibase_infra/runtime/util_version.py +98 -0
- omnibase_infra/runtime/util_wiring.py +723 -0
- omnibase_infra/schemas/schema_registration_projection.sql +320 -0
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/__init__.py +89 -0
- omnibase_infra/services/corpus_capture.py +684 -0
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +565 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +261 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +837 -0
- omnibase_infra/services/service_capability_query.py +945 -0
- omnibase_infra/services/service_health.py +898 -0
- omnibase_infra/services/service_node_selector.py +530 -0
- omnibase_infra/services/service_timeout_emitter.py +699 -0
- omnibase_infra/services/service_timeout_scanner.py +394 -0
- omnibase_infra/services/session/__init__.py +56 -0
- omnibase_infra/services/session/config_consumer.py +137 -0
- omnibase_infra/services/session/config_store.py +139 -0
- omnibase_infra/services/session/consumer.py +1007 -0
- omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
- omnibase_infra/services/session/store.py +997 -0
- omnibase_infra/services/snapshot/__init__.py +31 -0
- omnibase_infra/services/snapshot/service_snapshot.py +647 -0
- omnibase_infra/services/snapshot/store_inmemory.py +637 -0
- omnibase_infra/services/snapshot/store_postgres.py +1279 -0
- omnibase_infra/shared/__init__.py +8 -0
- omnibase_infra/testing/__init__.py +10 -0
- omnibase_infra/testing/utils.py +23 -0
- omnibase_infra/topics/__init__.py +45 -0
- omnibase_infra/topics/platform_topic_suffixes.py +140 -0
- omnibase_infra/topics/util_topic_composition.py +95 -0
- omnibase_infra/types/__init__.py +48 -0
- omnibase_infra/types/type_cache_info.py +49 -0
- omnibase_infra/types/type_dsn.py +173 -0
- omnibase_infra/types/type_infra_aliases.py +60 -0
- omnibase_infra/types/typed_dict/__init__.py +29 -0
- omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
- omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
- omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
- omnibase_infra/types/typed_dict_capabilities.py +64 -0
- omnibase_infra/utils/__init__.py +117 -0
- omnibase_infra/utils/correlation.py +208 -0
- omnibase_infra/utils/util_atomic_file.py +261 -0
- omnibase_infra/utils/util_consumer_group.py +232 -0
- omnibase_infra/utils/util_datetime.py +372 -0
- omnibase_infra/utils/util_db_transaction.py +239 -0
- omnibase_infra/utils/util_dsn_validation.py +333 -0
- omnibase_infra/utils/util_env_parsing.py +264 -0
- omnibase_infra/utils/util_error_sanitization.py +457 -0
- omnibase_infra/utils/util_pydantic_validators.py +477 -0
- omnibase_infra/utils/util_retry_optimistic.py +281 -0
- omnibase_infra/utils/util_semver.py +233 -0
- omnibase_infra/validation/__init__.py +307 -0
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/enums/__init__.py +11 -0
- omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
- omnibase_infra/validation/infra_validators.py +1514 -0
- omnibase_infra/validation/linter_contract.py +907 -0
- omnibase_infra/validation/mixin_any_type_classification.py +120 -0
- omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
- omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
- omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
- omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
- omnibase_infra/validation/models/__init__.py +15 -0
- omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
- omnibase_infra/validation/models/model_contract_violation.py +41 -0
- omnibase_infra/validation/service_validation_aggregator.py +395 -0
- omnibase_infra/validation/validation_exemptions.yaml +2033 -0
- omnibase_infra/validation/validator_any_type.py +715 -0
- omnibase_infra/validation/validator_chain_propagation.py +839 -0
- omnibase_infra/validation/validator_execution_shape.py +465 -0
- omnibase_infra/validation/validator_localhandler.py +261 -0
- omnibase_infra/validation/validator_registration_security.py +410 -0
- omnibase_infra/validation/validator_routing_coverage.py +1020 -0
- omnibase_infra/validation/validator_runtime_shape.py +915 -0
- omnibase_infra/validation/validator_security.py +513 -0
- omnibase_infra/validation/validator_topic_category.py +1152 -0
- omnibase_infra-0.2.6.dist-info/METADATA +197 -0
- omnibase_infra-0.2.6.dist-info/RECORD +833 -0
- omnibase_infra-0.2.6.dist-info/WHEEL +4 -0
- omnibase_infra-0.2.6.dist-info/entry_points.txt +5 -0
- omnibase_infra-0.2.6.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""HashiCorp Consul Handler - MVP implementation using python-consul client.
|
|
4
|
+
|
|
5
|
+
Supports service discovery operations with configurable retry logic and
|
|
6
|
+
circuit breaker pattern for fault tolerance.
|
|
7
|
+
|
|
8
|
+
Security Features:
|
|
9
|
+
- SecretStr protection for ACL tokens (prevents accidental logging)
|
|
10
|
+
- Sanitized error messages (never expose tokens in logs)
|
|
11
|
+
- Token handling follows security best practices
|
|
12
|
+
|
|
13
|
+
Supported Operations:
|
|
14
|
+
- consul.kv_get: Retrieve value from KV store
|
|
15
|
+
- consul.kv_put: Store value in KV store
|
|
16
|
+
- consul.register: Register service with Consul agent
|
|
17
|
+
- consul.deregister: Deregister service from Consul agent
|
|
18
|
+
|
|
19
|
+
Envelope-Based Routing:
|
|
20
|
+
This handler uses envelope-based operation routing. See CLAUDE.md section
|
|
21
|
+
"Intent Model Architecture > Envelope-Based Handler Routing" for the full
|
|
22
|
+
design pattern and how orchestrators translate intents to handler envelopes.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import asyncio
|
|
28
|
+
import logging
|
|
29
|
+
from collections.abc import Callable
|
|
30
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
31
|
+
from typing import NamedTuple, TypeVar
|
|
32
|
+
from uuid import UUID, uuid4
|
|
33
|
+
|
|
34
|
+
import consul
|
|
35
|
+
|
|
36
|
+
from omnibase_core.container import ModelONEXContainer
|
|
37
|
+
from omnibase_core.models.dispatch import ModelHandlerOutput
|
|
38
|
+
from omnibase_infra.enums import (
|
|
39
|
+
EnumHandlerType,
|
|
40
|
+
EnumHandlerTypeCategory,
|
|
41
|
+
EnumInfraTransportType,
|
|
42
|
+
EnumResponseStatus,
|
|
43
|
+
)
|
|
44
|
+
from omnibase_infra.errors import (
|
|
45
|
+
InfraAuthenticationError,
|
|
46
|
+
InfraConnectionError,
|
|
47
|
+
InfraConsulError,
|
|
48
|
+
ModelInfraErrorContext,
|
|
49
|
+
RuntimeHostError,
|
|
50
|
+
)
|
|
51
|
+
from omnibase_infra.handlers.mixins import (
|
|
52
|
+
MixinConsulInitialization,
|
|
53
|
+
MixinConsulKV,
|
|
54
|
+
MixinConsulService,
|
|
55
|
+
MixinConsulTopicIndex,
|
|
56
|
+
)
|
|
57
|
+
from omnibase_infra.handlers.models import (
|
|
58
|
+
ModelOperationContext,
|
|
59
|
+
ModelRetryState,
|
|
60
|
+
)
|
|
61
|
+
from omnibase_infra.handlers.models.consul import (
|
|
62
|
+
ConsulPayload,
|
|
63
|
+
ModelConsulHandlerConfig,
|
|
64
|
+
ModelConsulHandlerPayload,
|
|
65
|
+
)
|
|
66
|
+
from omnibase_infra.handlers.models.model_consul_handler_response import (
|
|
67
|
+
ModelConsulHandlerResponse,
|
|
68
|
+
)
|
|
69
|
+
from omnibase_infra.mixins import (
|
|
70
|
+
EnumRetryErrorCategory,
|
|
71
|
+
MixinAsyncCircuitBreaker,
|
|
72
|
+
MixinEnvelopeExtraction,
|
|
73
|
+
MixinRetryExecution,
|
|
74
|
+
ModelRetryErrorClassification,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
T = TypeVar("T")
|
|
78
|
+
|
|
79
|
+
logger = logging.getLogger(__name__)
|
|
80
|
+
|
|
81
|
+
# Handler ID for ModelHandlerOutput
|
|
82
|
+
HANDLER_ID_CONSUL: str = "consul-handler"
|
|
83
|
+
|
|
84
|
+
SUPPORTED_OPERATIONS: frozenset[str] = frozenset(
|
|
85
|
+
{
|
|
86
|
+
"consul.kv_get",
|
|
87
|
+
"consul.kv_put",
|
|
88
|
+
"consul.register",
|
|
89
|
+
"consul.deregister",
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class RetryContext(NamedTuple):
|
|
95
|
+
"""Context for retry operations containing state and operation metadata.
|
|
96
|
+
|
|
97
|
+
This named tuple provides clear field access for retry initialization,
|
|
98
|
+
improving code clarity over plain tuples.
|
|
99
|
+
|
|
100
|
+
Attributes:
|
|
101
|
+
retry_state: Current retry state including attempt count and delays.
|
|
102
|
+
operation_context: Operation context with correlation ID and timeout.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
retry_state: ModelRetryState
|
|
106
|
+
operation_context: ModelOperationContext
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class HandlerConsul(
|
|
110
|
+
MixinAsyncCircuitBreaker,
|
|
111
|
+
MixinRetryExecution,
|
|
112
|
+
MixinEnvelopeExtraction,
|
|
113
|
+
MixinConsulInitialization,
|
|
114
|
+
MixinConsulKV,
|
|
115
|
+
MixinConsulTopicIndex, # Must come before MixinConsulService (MRO order)
|
|
116
|
+
MixinConsulService,
|
|
117
|
+
):
|
|
118
|
+
"""HashiCorp Consul handler using python-consul client (MVP: KV, service registration).
|
|
119
|
+
|
|
120
|
+
Security Policy - Token Handling:
|
|
121
|
+
The Consul ACL token contains sensitive credentials and is treated as a secret
|
|
122
|
+
throughout this handler. The following security measures are enforced:
|
|
123
|
+
|
|
124
|
+
1. Token is stored as SecretStr in config (never logged or exposed)
|
|
125
|
+
2. All error messages use generic descriptions without exposing token
|
|
126
|
+
3. The describe() method returns capabilities without credentials
|
|
127
|
+
|
|
128
|
+
See CLAUDE.md "Error Sanitization Guidelines" for the full security policy
|
|
129
|
+
on what information is safe vs unsafe to include in errors and logs.
|
|
130
|
+
|
|
131
|
+
Thread Pool Management (Production-Grade):
|
|
132
|
+
- Bounded ThreadPoolExecutor prevents resource exhaustion
|
|
133
|
+
- Configurable max_concurrent_operations (default: 10, max: 100)
|
|
134
|
+
- Thread pool gracefully shutdown on handler.shutdown()
|
|
135
|
+
- All consul (synchronous) operations run in dedicated thread pool
|
|
136
|
+
|
|
137
|
+
Queue Size Management (MVP Behavior):
|
|
138
|
+
ThreadPoolExecutor uses an unbounded queue by default. The max_queue_size
|
|
139
|
+
parameter is calculated (max_workers * multiplier) for monitoring purposes,
|
|
140
|
+
but is NOT enforced by the executor.
|
|
141
|
+
|
|
142
|
+
Why unbounded is acceptable for MVP:
|
|
143
|
+
- Consul operations are typically short-lived (KV get/put)
|
|
144
|
+
- Circuit breaker provides backpressure when Consul is unavailable
|
|
145
|
+
- Thread pool size limits concurrent execution (default: 10 workers)
|
|
146
|
+
- Memory exhaustion from queue growth is unlikely in normal operation
|
|
147
|
+
|
|
148
|
+
Future Enhancement Path:
|
|
149
|
+
For production deployments with strict resource controls, implement a
|
|
150
|
+
custom executor with bounded queue using queue.Queue(maxsize=N):
|
|
151
|
+
|
|
152
|
+
from queue import Queue
|
|
153
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
154
|
+
|
|
155
|
+
class BoundedThreadPoolExecutor(ThreadPoolExecutor):
|
|
156
|
+
def __init__(self, max_workers, max_queue_size):
|
|
157
|
+
super().__init__(max_workers)
|
|
158
|
+
self._work_queue = Queue(maxsize=max_queue_size)
|
|
159
|
+
|
|
160
|
+
This would reject tasks when queue is full, enabling explicit backpressure.
|
|
161
|
+
|
|
162
|
+
Circuit Breaker Pattern (Production-Grade):
|
|
163
|
+
- Uses MixinAsyncCircuitBreaker for consistent circuit breaker implementation
|
|
164
|
+
- Prevents cascading failures to Consul service
|
|
165
|
+
- Three states: CLOSED (normal), OPEN (blocking), HALF_OPEN (testing)
|
|
166
|
+
- Configurable failure_threshold (default: 5 consecutive failures)
|
|
167
|
+
- Configurable reset_timeout (default: 30 seconds)
|
|
168
|
+
- Raises InfraUnavailableError when circuit is OPEN
|
|
169
|
+
|
|
170
|
+
Retry Logic:
|
|
171
|
+
- All operations use exponential backoff retry logic
|
|
172
|
+
- Retry configuration from ModelConsulRetryConfig
|
|
173
|
+
- Backoff calculation: initial_delay * (exponential_base ** attempt)
|
|
174
|
+
- Max backoff capped at max_delay_seconds
|
|
175
|
+
- Circuit breaker checked before retry execution
|
|
176
|
+
|
|
177
|
+
Error Context Design:
|
|
178
|
+
Error contexts use static target_name="consul_handler" for consistency with
|
|
179
|
+
HandlerVault and other infrastructure handlers. This provides predictable
|
|
180
|
+
error categorization and log filtering across all Consul operations.
|
|
181
|
+
|
|
182
|
+
For multi-DC deployments, datacenter differentiation is achieved via:
|
|
183
|
+
- Circuit breaker service_name (e.g., "consul.dc1", "consul.dc2")
|
|
184
|
+
- Structured logging with datacenter field in extra dict
|
|
185
|
+
- Correlation IDs that can be traced across datacenters
|
|
186
|
+
|
|
187
|
+
This design keeps error aggregation unified (all Consul errors grouped under
|
|
188
|
+
"consul_handler") while still providing operational visibility per-datacenter
|
|
189
|
+
through circuit breaker metrics and structured logs.
|
|
190
|
+
|
|
191
|
+
Future Enhancement: If error differentiation per-DC becomes a requirement
|
|
192
|
+
(e.g., for DC-specific alerting), target_name could be made dynamic:
|
|
193
|
+
target_name=f"consul.{self._config.datacenter or 'default'}"
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def __init__(self, container: ModelONEXContainer) -> None:
|
|
197
|
+
"""Initialize HandlerConsul in uninitialized state.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
container: ONEX container for dependency injection. Required for
|
|
201
|
+
consistent handler initialization pattern across all handlers.
|
|
202
|
+
|
|
203
|
+
Note: Circuit breaker is initialized during initialize() call when
|
|
204
|
+
configuration is available. The mixin's _init_circuit_breaker() method
|
|
205
|
+
is called there with the actual config values.
|
|
206
|
+
"""
|
|
207
|
+
self._container = container
|
|
208
|
+
self._client: consul.Consul | None = None
|
|
209
|
+
self._config: ModelConsulHandlerConfig | None = None
|
|
210
|
+
self._initialized: bool = False
|
|
211
|
+
self._executor: ThreadPoolExecutor | None = None
|
|
212
|
+
self._max_workers: int = 0
|
|
213
|
+
self._max_queue_size: int = 0
|
|
214
|
+
# Circuit breaker initialized flag - set after _init_circuit_breaker called
|
|
215
|
+
self._circuit_breaker_initialized: bool = False
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def handler_type(self) -> EnumHandlerType:
|
|
219
|
+
"""Return the architectural role of this handler.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
EnumHandlerType.INFRA_HANDLER - This handler is an infrastructure
|
|
223
|
+
protocol/transport handler (as opposed to NODE_HANDLER for event
|
|
224
|
+
processing, PROJECTION_HANDLER for read models, or COMPUTE_HANDLER
|
|
225
|
+
for pure computation).
|
|
226
|
+
|
|
227
|
+
Note:
|
|
228
|
+
handler_type determines lifecycle, protocol selection, and runtime
|
|
229
|
+
invocation patterns. It answers "what is this handler in the architecture?"
|
|
230
|
+
|
|
231
|
+
See Also:
|
|
232
|
+
- handler_category: Behavioral classification (EFFECT/COMPUTE)
|
|
233
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
234
|
+
"""
|
|
235
|
+
return EnumHandlerType.INFRA_HANDLER
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def handler_category(self) -> EnumHandlerTypeCategory:
|
|
239
|
+
"""Return the behavioral classification of this handler.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
EnumHandlerTypeCategory.EFFECT - This handler performs side-effecting
|
|
243
|
+
I/O operations (Consul KV store and service registry). EFFECT handlers
|
|
244
|
+
are not deterministic and interact with external systems.
|
|
245
|
+
|
|
246
|
+
Note:
|
|
247
|
+
handler_category determines security rules, determinism guarantees,
|
|
248
|
+
replay safety, and permissions. It answers "how does this handler
|
|
249
|
+
behave at runtime?"
|
|
250
|
+
|
|
251
|
+
Categories:
|
|
252
|
+
- COMPUTE: Pure, deterministic transformations (no side effects)
|
|
253
|
+
- EFFECT: Side-effecting I/O (database, HTTP, service calls)
|
|
254
|
+
- NONDETERMINISTIC_COMPUTE: Pure but not deterministic (UUID, random)
|
|
255
|
+
|
|
256
|
+
See Also:
|
|
257
|
+
- handler_type: Architectural role (INFRA_HANDLER/NODE_HANDLER/etc.)
|
|
258
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
259
|
+
"""
|
|
260
|
+
return EnumHandlerTypeCategory.EFFECT
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def max_workers(self) -> int:
|
|
264
|
+
"""Return thread pool max workers (public API for tests)."""
|
|
265
|
+
return self._max_workers
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def max_queue_size(self) -> int:
|
|
269
|
+
"""Return maximum queue size (public API for tests)."""
|
|
270
|
+
return self._max_queue_size
|
|
271
|
+
|
|
272
|
+
# MixinRetryExecution abstract method implementations
|
|
273
|
+
|
|
274
|
+
def _get_transport_type(self) -> EnumInfraTransportType:
|
|
275
|
+
"""Return transport type for error context."""
|
|
276
|
+
return EnumInfraTransportType.CONSUL
|
|
277
|
+
|
|
278
|
+
def _get_target_name(self) -> str:
|
|
279
|
+
"""Return target name for error context."""
|
|
280
|
+
return "consul_handler"
|
|
281
|
+
|
|
282
|
+
def _classify_error(
|
|
283
|
+
self, error: Exception, operation: str
|
|
284
|
+
) -> ModelRetryErrorClassification:
|
|
285
|
+
"""Classify Consul-specific exceptions for retry handling.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
error: The exception to classify.
|
|
289
|
+
operation: The operation name for context.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
ModelRetryErrorClassification with retry decision and error details.
|
|
293
|
+
"""
|
|
294
|
+
if isinstance(error, TimeoutError):
|
|
295
|
+
return ModelRetryErrorClassification(
|
|
296
|
+
category=EnumRetryErrorCategory.TIMEOUT,
|
|
297
|
+
should_retry=True,
|
|
298
|
+
record_circuit_failure=True,
|
|
299
|
+
error_message=f"Timeout: {type(error).__name__}",
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
if isinstance(error, consul.ACLPermissionDenied):
|
|
303
|
+
return ModelRetryErrorClassification(
|
|
304
|
+
category=EnumRetryErrorCategory.AUTHENTICATION,
|
|
305
|
+
should_retry=False,
|
|
306
|
+
record_circuit_failure=True,
|
|
307
|
+
error_message="Consul ACL permission denied - check token permissions",
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
if isinstance(error, consul.Timeout):
|
|
311
|
+
return ModelRetryErrorClassification(
|
|
312
|
+
category=EnumRetryErrorCategory.TIMEOUT,
|
|
313
|
+
should_retry=True,
|
|
314
|
+
record_circuit_failure=True,
|
|
315
|
+
error_message=f"Consul timeout: {type(error).__name__}",
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if isinstance(error, consul.ConsulException):
|
|
319
|
+
return ModelRetryErrorClassification(
|
|
320
|
+
category=EnumRetryErrorCategory.CONNECTION,
|
|
321
|
+
should_retry=True,
|
|
322
|
+
record_circuit_failure=True,
|
|
323
|
+
error_message=f"Consul error: {type(error).__name__}",
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Unknown error - retry eligible
|
|
327
|
+
return ModelRetryErrorClassification(
|
|
328
|
+
category=EnumRetryErrorCategory.UNKNOWN,
|
|
329
|
+
should_retry=True,
|
|
330
|
+
record_circuit_failure=True,
|
|
331
|
+
error_message=f"Unexpected error: {type(error).__name__}",
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
async def initialize(self, config: dict[str, object]) -> None:
|
|
335
|
+
"""Initialize Consul client with configuration.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
config: Configuration dict containing:
|
|
339
|
+
- host: Consul server hostname (default: "localhost")
|
|
340
|
+
- port: Consul server port (default: 8500)
|
|
341
|
+
- scheme: HTTP scheme "http" or "https" (default: "http")
|
|
342
|
+
- token: Optional Consul ACL token
|
|
343
|
+
- timeout_seconds: Optional timeout (default 30.0)
|
|
344
|
+
- datacenter: Optional datacenter for multi-DC deployments
|
|
345
|
+
|
|
346
|
+
Raises:
|
|
347
|
+
ProtocolConfigurationError: If configuration validation fails.
|
|
348
|
+
InfraAuthenticationError: If token authentication fails.
|
|
349
|
+
InfraConnectionError: If connection to Consul server fails.
|
|
350
|
+
RuntimeHostError: If client initialization fails for other reasons.
|
|
351
|
+
|
|
352
|
+
Security:
|
|
353
|
+
Token must be provided via environment variable, not hardcoded in config.
|
|
354
|
+
Use SecretStr for token to prevent accidental logging.
|
|
355
|
+
"""
|
|
356
|
+
init_correlation_id = uuid4()
|
|
357
|
+
|
|
358
|
+
logger.info(
|
|
359
|
+
"Initializing %s",
|
|
360
|
+
self.__class__.__name__,
|
|
361
|
+
extra={
|
|
362
|
+
"handler": self.__class__.__name__,
|
|
363
|
+
"correlation_id": str(init_correlation_id),
|
|
364
|
+
},
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# Validate configuration
|
|
368
|
+
self._config = self._validate_consul_config(config, init_correlation_id)
|
|
369
|
+
|
|
370
|
+
# Set up client and infrastructure
|
|
371
|
+
try:
|
|
372
|
+
self._client = self._setup_consul_client(self._config)
|
|
373
|
+
self._verify_consul_connection(self._client, init_correlation_id)
|
|
374
|
+
self._setup_thread_pool(self._config)
|
|
375
|
+
self._setup_circuit_breaker(self._config)
|
|
376
|
+
|
|
377
|
+
self._initialized = True
|
|
378
|
+
self._log_initialization_success(self._config, init_correlation_id)
|
|
379
|
+
|
|
380
|
+
except (InfraConnectionError, InfraAuthenticationError):
|
|
381
|
+
raise
|
|
382
|
+
except consul.ACLPermissionDenied as e:
|
|
383
|
+
self._raise_auth_error(init_correlation_id, e)
|
|
384
|
+
except consul.ConsulException as e:
|
|
385
|
+
self._raise_connection_error(init_correlation_id, e)
|
|
386
|
+
except Exception as e:
|
|
387
|
+
self._raise_runtime_error(init_correlation_id, e)
|
|
388
|
+
|
|
389
|
+
async def shutdown(self) -> None:
|
|
390
|
+
"""Close Consul client and release resources.
|
|
391
|
+
|
|
392
|
+
Cleanup includes:
|
|
393
|
+
- Shutting down thread pool executor (waits for pending tasks)
|
|
394
|
+
- Clearing Consul client connection
|
|
395
|
+
- Resetting circuit breaker state (thread-safe via mixin)
|
|
396
|
+
"""
|
|
397
|
+
shutdown_correlation_id = uuid4()
|
|
398
|
+
|
|
399
|
+
if self._executor is not None:
|
|
400
|
+
# Shutdown thread pool gracefully (wait for pending tasks)
|
|
401
|
+
self._executor.shutdown(wait=True)
|
|
402
|
+
self._executor = None
|
|
403
|
+
|
|
404
|
+
if self._client is not None:
|
|
405
|
+
# python-consul.Client doesn't have close method, just clear reference
|
|
406
|
+
self._client = None
|
|
407
|
+
|
|
408
|
+
# Reset circuit breaker state using mixin (thread-safe)
|
|
409
|
+
if self._circuit_breaker_initialized:
|
|
410
|
+
async with self._circuit_breaker_lock:
|
|
411
|
+
await self._reset_circuit_breaker()
|
|
412
|
+
|
|
413
|
+
self._initialized = False
|
|
414
|
+
self._config = None
|
|
415
|
+
self._circuit_breaker_initialized = False
|
|
416
|
+
logger.info(
|
|
417
|
+
"HandlerConsul shutdown complete",
|
|
418
|
+
extra={
|
|
419
|
+
"correlation_id": str(shutdown_correlation_id),
|
|
420
|
+
},
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
def _build_response(
|
|
424
|
+
self,
|
|
425
|
+
typed_payload: ConsulPayload,
|
|
426
|
+
correlation_id: UUID,
|
|
427
|
+
input_envelope_id: UUID,
|
|
428
|
+
) -> ModelHandlerOutput[ModelConsulHandlerResponse]:
|
|
429
|
+
"""Build standardized ModelConsulHandlerResponse wrapped in ModelHandlerOutput.
|
|
430
|
+
|
|
431
|
+
This helper method ensures consistent response formatting across all
|
|
432
|
+
Consul operations, matching the pattern used by HandlerDb.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
typed_payload: Strongly-typed payload from the discriminated union.
|
|
436
|
+
correlation_id: Correlation ID for tracing.
|
|
437
|
+
input_envelope_id: Input envelope ID for causality tracking.
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
ModelHandlerOutput wrapping ModelConsulHandlerResponse.
|
|
441
|
+
"""
|
|
442
|
+
response = ModelConsulHandlerResponse(
|
|
443
|
+
status=EnumResponseStatus.SUCCESS,
|
|
444
|
+
payload=ModelConsulHandlerPayload(data=typed_payload),
|
|
445
|
+
correlation_id=correlation_id,
|
|
446
|
+
)
|
|
447
|
+
return ModelHandlerOutput.for_compute(
|
|
448
|
+
input_envelope_id=input_envelope_id,
|
|
449
|
+
correlation_id=correlation_id,
|
|
450
|
+
handler_id=HANDLER_ID_CONSUL,
|
|
451
|
+
result=response,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
async def execute(
|
|
455
|
+
self, envelope: dict[str, object]
|
|
456
|
+
) -> ModelHandlerOutput[ModelConsulHandlerResponse]:
|
|
457
|
+
"""Execute Consul operation from envelope.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
envelope: Request envelope containing:
|
|
461
|
+
- operation: Consul operation (consul.kv_get, consul.kv_put, etc.)
|
|
462
|
+
- payload: dict with operation-specific parameters
|
|
463
|
+
- correlation_id: Optional correlation ID for tracing
|
|
464
|
+
- envelope_id: Optional envelope ID for causality tracking
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
ModelHandlerOutput wrapping the operation result with correlation tracking
|
|
468
|
+
|
|
469
|
+
Raises:
|
|
470
|
+
RuntimeHostError: If handler not initialized or invalid input.
|
|
471
|
+
InfraConnectionError: If Consul connection fails.
|
|
472
|
+
InfraAuthenticationError: If authentication fails.
|
|
473
|
+
InfraUnavailableError: If circuit breaker is open.
|
|
474
|
+
"""
|
|
475
|
+
correlation_id = self._extract_correlation_id(envelope)
|
|
476
|
+
input_envelope_id = self._extract_envelope_id(envelope)
|
|
477
|
+
|
|
478
|
+
if not self._initialized or self._client is None or self._config is None:
|
|
479
|
+
ctx = ModelInfraErrorContext(
|
|
480
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
481
|
+
operation="execute",
|
|
482
|
+
target_name="consul_handler",
|
|
483
|
+
correlation_id=correlation_id,
|
|
484
|
+
)
|
|
485
|
+
raise RuntimeHostError(
|
|
486
|
+
"Consul client not initialized for operation 'execute'. "
|
|
487
|
+
"Call initialize() first.",
|
|
488
|
+
context=ctx,
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
operation = envelope.get("operation")
|
|
492
|
+
if not isinstance(operation, str):
|
|
493
|
+
ctx = ModelInfraErrorContext(
|
|
494
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
495
|
+
operation="execute",
|
|
496
|
+
target_name="consul_handler",
|
|
497
|
+
correlation_id=correlation_id,
|
|
498
|
+
)
|
|
499
|
+
raise RuntimeHostError(
|
|
500
|
+
"Missing or invalid 'operation' in envelope",
|
|
501
|
+
context=ctx,
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
if operation not in SUPPORTED_OPERATIONS:
|
|
505
|
+
ctx = ModelInfraErrorContext(
|
|
506
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
507
|
+
operation=operation,
|
|
508
|
+
target_name="consul_handler",
|
|
509
|
+
correlation_id=correlation_id,
|
|
510
|
+
)
|
|
511
|
+
raise RuntimeHostError(
|
|
512
|
+
f"Operation '{operation}' not supported in MVP. "
|
|
513
|
+
f"Available: {', '.join(sorted(SUPPORTED_OPERATIONS))}",
|
|
514
|
+
context=ctx,
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
payload = envelope.get("payload")
|
|
518
|
+
if not isinstance(payload, dict):
|
|
519
|
+
ctx = ModelInfraErrorContext(
|
|
520
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
521
|
+
operation=operation,
|
|
522
|
+
target_name="consul_handler",
|
|
523
|
+
correlation_id=correlation_id,
|
|
524
|
+
)
|
|
525
|
+
raise RuntimeHostError(
|
|
526
|
+
"Missing or invalid 'payload' in envelope",
|
|
527
|
+
context=ctx,
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
# Route to appropriate handler
|
|
531
|
+
if operation == "consul.kv_get":
|
|
532
|
+
return await self._kv_get(payload, correlation_id, input_envelope_id)
|
|
533
|
+
elif operation == "consul.kv_put":
|
|
534
|
+
return await self._kv_put(payload, correlation_id, input_envelope_id)
|
|
535
|
+
elif operation == "consul.register":
|
|
536
|
+
return await self._register_service(
|
|
537
|
+
payload, correlation_id, input_envelope_id
|
|
538
|
+
)
|
|
539
|
+
else: # consul.deregister - validated above, guaranteed to be deregister
|
|
540
|
+
return await self._deregister_service(
|
|
541
|
+
payload, correlation_id, input_envelope_id
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
async def _execute_with_retry(
|
|
545
|
+
self,
|
|
546
|
+
operation: str,
|
|
547
|
+
func: Callable[[], T],
|
|
548
|
+
correlation_id: UUID,
|
|
549
|
+
) -> T:
|
|
550
|
+
"""Execute operation with exponential backoff retry logic and circuit breaker.
|
|
551
|
+
|
|
552
|
+
Thread-Safety:
|
|
553
|
+
This method is concurrency-safe. Each call maintains its own retry
|
|
554
|
+
state stack, with no shared mutable state between concurrent operations.
|
|
555
|
+
This allows multiple operations to execute in parallel without
|
|
556
|
+
interfering with each other's retry logic.
|
|
557
|
+
|
|
558
|
+
Thread Pool Integration:
|
|
559
|
+
All consul operations (which are synchronous) are executed in a dedicated
|
|
560
|
+
thread pool via loop.run_in_executor(). This prevents blocking the async
|
|
561
|
+
event loop and allows concurrent Consul operations up to max_workers limit.
|
|
562
|
+
|
|
563
|
+
Circuit breaker integration (via MixinAsyncCircuitBreaker):
|
|
564
|
+
- Checks circuit state before execution (raises if OPEN)
|
|
565
|
+
- Records success/failure for circuit state management
|
|
566
|
+
- Allows test request in HALF_OPEN state
|
|
567
|
+
|
|
568
|
+
Args:
|
|
569
|
+
operation: Operation name for logging
|
|
570
|
+
func: Callable to execute (synchronous consul method)
|
|
571
|
+
correlation_id: Correlation ID for tracing
|
|
572
|
+
|
|
573
|
+
Returns:
|
|
574
|
+
Result from func()
|
|
575
|
+
|
|
576
|
+
Raises:
|
|
577
|
+
InfraTimeoutError: If all retries exhausted or operation times out
|
|
578
|
+
InfraConnectionError: If connection fails
|
|
579
|
+
InfraAuthenticationError: If authentication fails
|
|
580
|
+
InfraUnavailableError: If circuit breaker is OPEN
|
|
581
|
+
"""
|
|
582
|
+
if self._config is None:
|
|
583
|
+
context = ModelInfraErrorContext(
|
|
584
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
585
|
+
operation=operation,
|
|
586
|
+
target_name="consul_handler",
|
|
587
|
+
correlation_id=correlation_id,
|
|
588
|
+
)
|
|
589
|
+
raise InfraConsulError("Consul config not initialized", context=context)
|
|
590
|
+
|
|
591
|
+
await self._check_circuit_if_enabled(operation, correlation_id)
|
|
592
|
+
|
|
593
|
+
ctx = self._init_retry_context(operation, correlation_id)
|
|
594
|
+
retry_state = ctx.retry_state
|
|
595
|
+
op_context = ctx.operation_context
|
|
596
|
+
|
|
597
|
+
# Track last exception for proper error chaining when retries exhaust
|
|
598
|
+
last_exception: Exception | None = None
|
|
599
|
+
|
|
600
|
+
while retry_state.is_retriable():
|
|
601
|
+
(
|
|
602
|
+
result_tuple,
|
|
603
|
+
retry_state,
|
|
604
|
+
caught_exception,
|
|
605
|
+
) = await self._try_execute_operation(
|
|
606
|
+
func, retry_state, op_context, operation, correlation_id
|
|
607
|
+
)
|
|
608
|
+
if result_tuple is not None:
|
|
609
|
+
return result_tuple[0] # Unpack the result tuple
|
|
610
|
+
|
|
611
|
+
# Track the last exception for error chaining
|
|
612
|
+
last_exception = caught_exception
|
|
613
|
+
|
|
614
|
+
await self._log_retry_attempt(operation, retry_state, correlation_id)
|
|
615
|
+
await asyncio.sleep(retry_state.delay_seconds)
|
|
616
|
+
|
|
617
|
+
# Should never reach here, but satisfy type checker
|
|
618
|
+
context = ModelInfraErrorContext(
|
|
619
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
620
|
+
operation=operation,
|
|
621
|
+
target_name="consul_handler",
|
|
622
|
+
correlation_id=correlation_id,
|
|
623
|
+
)
|
|
624
|
+
if retry_state.last_error is not None:
|
|
625
|
+
# Chain to original exception to preserve root cause for debugging
|
|
626
|
+
raise InfraConsulError(
|
|
627
|
+
f"Retry exhausted: {retry_state.last_error}",
|
|
628
|
+
context=context,
|
|
629
|
+
) from last_exception
|
|
630
|
+
raise InfraConsulError(
|
|
631
|
+
"Retry loop completed without result",
|
|
632
|
+
context=context,
|
|
633
|
+
) from last_exception
|
|
634
|
+
|
|
635
|
+
def _init_retry_context(self, operation: str, correlation_id: UUID) -> RetryContext:
|
|
636
|
+
"""Initialize retry state and operation context.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
operation: Operation name for context.
|
|
640
|
+
correlation_id: Correlation ID for tracing.
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
RetryContext with initialized retry_state and operation_context.
|
|
644
|
+
"""
|
|
645
|
+
if self._config is None:
|
|
646
|
+
context = ModelInfraErrorContext(
|
|
647
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
648
|
+
operation=operation,
|
|
649
|
+
target_name="consul_handler",
|
|
650
|
+
correlation_id=correlation_id,
|
|
651
|
+
)
|
|
652
|
+
raise InfraConsulError("Consul config not initialized", context=context)
|
|
653
|
+
|
|
654
|
+
retry_config = self._config.retry
|
|
655
|
+
retry_state = ModelRetryState(
|
|
656
|
+
attempt=0,
|
|
657
|
+
max_attempts=retry_config.max_attempts,
|
|
658
|
+
delay_seconds=retry_config.initial_delay_seconds,
|
|
659
|
+
backoff_multiplier=retry_config.exponential_base,
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
op_context = ModelOperationContext.create(
|
|
663
|
+
operation_name=operation,
|
|
664
|
+
correlation_id=correlation_id,
|
|
665
|
+
timeout_seconds=self._config.timeout_seconds,
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
return RetryContext(
|
|
669
|
+
retry_state=retry_state,
|
|
670
|
+
operation_context=op_context,
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
async def _try_execute_operation(
|
|
674
|
+
self,
|
|
675
|
+
func: Callable[[], T],
|
|
676
|
+
retry_state: ModelRetryState,
|
|
677
|
+
op_context: ModelOperationContext,
|
|
678
|
+
operation: str,
|
|
679
|
+
correlation_id: UUID,
|
|
680
|
+
) -> (
|
|
681
|
+
tuple[tuple[T], ModelRetryState, None] | tuple[None, ModelRetryState, Exception]
|
|
682
|
+
):
|
|
683
|
+
"""Try to execute an operation once with error handling.
|
|
684
|
+
|
|
685
|
+
Thread-Safety:
|
|
686
|
+
This method is concurrency-safe. All retry state is passed explicitly
|
|
687
|
+
as parameters and returned as values. No shared mutable state is used.
|
|
688
|
+
This allows multiple concurrent operations to execute independently.
|
|
689
|
+
|
|
690
|
+
Args:
|
|
691
|
+
func: Callable to execute.
|
|
692
|
+
retry_state: Current retry state.
|
|
693
|
+
op_context: Operation context.
|
|
694
|
+
operation: Operation name.
|
|
695
|
+
correlation_id: Correlation ID.
|
|
696
|
+
|
|
697
|
+
Returns:
|
|
698
|
+
Tuple of ((result,), retry_state, None) if successful.
|
|
699
|
+
Tuple of (None, updated_retry_state, exception) if should retry.
|
|
700
|
+
The exception is returned to enable proper error chaining when
|
|
701
|
+
retries are eventually exhausted.
|
|
702
|
+
|
|
703
|
+
Raises:
|
|
704
|
+
InfraTimeoutError, InfraConnectionError, InfraAuthenticationError:
|
|
705
|
+
If error is not retriable or retries are exhausted.
|
|
706
|
+
"""
|
|
707
|
+
if self._config is None:
|
|
708
|
+
context = ModelInfraErrorContext(
|
|
709
|
+
transport_type=EnumInfraTransportType.CONSUL,
|
|
710
|
+
operation=operation,
|
|
711
|
+
target_name="consul_handler",
|
|
712
|
+
correlation_id=correlation_id,
|
|
713
|
+
)
|
|
714
|
+
raise InfraConsulError("Consul config not initialized", context=context)
|
|
715
|
+
|
|
716
|
+
retry_config = self._config.retry
|
|
717
|
+
try:
|
|
718
|
+
loop = asyncio.get_running_loop()
|
|
719
|
+
result = await asyncio.wait_for(
|
|
720
|
+
loop.run_in_executor(self._executor, func),
|
|
721
|
+
timeout=op_context.timeout_seconds,
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
await self._reset_circuit_if_enabled()
|
|
725
|
+
return (result,), retry_state, None
|
|
726
|
+
|
|
727
|
+
except Exception as e:
|
|
728
|
+
classification = self._classify_error(e, operation)
|
|
729
|
+
|
|
730
|
+
if not classification.should_retry:
|
|
731
|
+
error = await self._handle_non_retriable_error(
|
|
732
|
+
classification, operation, correlation_id, e
|
|
733
|
+
)
|
|
734
|
+
raise error from e
|
|
735
|
+
|
|
736
|
+
new_state, error_to_raise = await self._handle_retriable_error(
|
|
737
|
+
classification,
|
|
738
|
+
retry_state,
|
|
739
|
+
retry_config.max_delay_seconds,
|
|
740
|
+
operation,
|
|
741
|
+
correlation_id,
|
|
742
|
+
op_context,
|
|
743
|
+
e,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
if error_to_raise is not None:
|
|
747
|
+
raise error_to_raise from e
|
|
748
|
+
|
|
749
|
+
return None, new_state, e
|
|
750
|
+
|
|
751
|
+
def describe(self) -> dict[str, object]:
|
|
752
|
+
"""Return handler metadata and capabilities for introspection.
|
|
753
|
+
|
|
754
|
+
This method exposes the handler's type classification along with its
|
|
755
|
+
operational configuration and capabilities.
|
|
756
|
+
|
|
757
|
+
Returns:
|
|
758
|
+
dict containing:
|
|
759
|
+
- handler_type: Architectural role from handler_type property
|
|
760
|
+
(e.g., "infra_handler"). See EnumHandlerType for valid values.
|
|
761
|
+
- handler_category: Behavioral classification from handler_category
|
|
762
|
+
property (e.g., "effect"). See EnumHandlerTypeCategory for valid values.
|
|
763
|
+
- supported_operations: List of supported operations
|
|
764
|
+
- timeout_seconds: Request timeout in seconds
|
|
765
|
+
- initialized: Whether the handler is initialized
|
|
766
|
+
- version: Handler version string
|
|
767
|
+
|
|
768
|
+
Note:
|
|
769
|
+
The handler_type and handler_category fields form the handler
|
|
770
|
+
classification system:
|
|
771
|
+
|
|
772
|
+
1. handler_type (architectural role): Determines lifecycle and invocation
|
|
773
|
+
patterns. This handler is INFRA_HANDLER (protocol/transport handler).
|
|
774
|
+
|
|
775
|
+
2. handler_category (behavioral classification): Determines security rules
|
|
776
|
+
and replay safety. This handler is EFFECT (side-effecting I/O).
|
|
777
|
+
|
|
778
|
+
The transport type for this handler is CONSUL (service discovery).
|
|
779
|
+
|
|
780
|
+
See Also:
|
|
781
|
+
- handler_type property: Full documentation of architectural role
|
|
782
|
+
- handler_category property: Full documentation of behavioral classification
|
|
783
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
784
|
+
"""
|
|
785
|
+
return {
|
|
786
|
+
"handler_type": self.handler_type.value,
|
|
787
|
+
"handler_category": self.handler_category.value,
|
|
788
|
+
"supported_operations": sorted(SUPPORTED_OPERATIONS),
|
|
789
|
+
"timeout_seconds": self._config.timeout_seconds if self._config else 30.0,
|
|
790
|
+
"initialized": self._initialized,
|
|
791
|
+
"version": "0.1.0-mvp",
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
__all__: list[str] = ["HandlerConsul", "RetryContext"]
|