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,699 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Timeout Emitter for emitting timeout events and updating markers.
|
|
4
|
+
|
|
5
|
+
This emitter handles the emission of timeout decision events and updates
|
|
6
|
+
the projection's emission markers to ensure exactly-once semantics.
|
|
7
|
+
|
|
8
|
+
The pattern is:
|
|
9
|
+
1. Query for overdue entities (via TimeoutScanner)
|
|
10
|
+
2. For each overdue entity:
|
|
11
|
+
a. Emit the appropriate timeout event
|
|
12
|
+
b. Update the emission marker in projection
|
|
13
|
+
3. If restart occurs, only emit for entities without markers
|
|
14
|
+
|
|
15
|
+
This ensures restart-safe, exactly-once timeout event emission.
|
|
16
|
+
|
|
17
|
+
Coroutine Safety:
|
|
18
|
+
This emitter is stateless and delegates coroutine safety to underlying
|
|
19
|
+
components (event_bus, projector). Multiple coroutines may call
|
|
20
|
+
process_timeouts concurrently as long as underlying components
|
|
21
|
+
support concurrent access.
|
|
22
|
+
|
|
23
|
+
Related Tickets:
|
|
24
|
+
- OMN-932 (C2): Durable Timeout Handling
|
|
25
|
+
- OMN-944 (F1): Implement Registration Projection Schema
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import logging
|
|
31
|
+
import time
|
|
32
|
+
from collections.abc import Sequence
|
|
33
|
+
from datetime import datetime
|
|
34
|
+
from typing import TYPE_CHECKING
|
|
35
|
+
from uuid import UUID
|
|
36
|
+
|
|
37
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
38
|
+
|
|
39
|
+
from omnibase_core.container import ModelONEXContainer
|
|
40
|
+
from omnibase_core.models.events.model_event_envelope import ModelEventEnvelope
|
|
41
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
42
|
+
from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
|
|
43
|
+
from omnibase_infra.models.projection import ModelRegistrationProjection
|
|
44
|
+
from omnibase_infra.services.service_timeout_scanner import ServiceTimeoutScanner
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
# Import protocols inside TYPE_CHECKING to avoid circular imports.
|
|
48
|
+
# ProtocolEventBus is used only for type annotations.
|
|
49
|
+
from omnibase_core.protocols.event_bus.protocol_event_bus import ProtocolEventBus
|
|
50
|
+
from omnibase_infra.runtime.projector_shell import ProjectorShell
|
|
51
|
+
|
|
52
|
+
logger = logging.getLogger(__name__)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ModelTimeoutEmissionResult(BaseModel):
|
|
56
|
+
"""Result of timeout emission processing.
|
|
57
|
+
|
|
58
|
+
Captures statistics about the timeout emission process for observability
|
|
59
|
+
and monitoring. This model is returned by process_timeouts() to inform
|
|
60
|
+
callers about what was emitted and any errors encountered.
|
|
61
|
+
|
|
62
|
+
Counter Semantics (Important):
|
|
63
|
+
All counters track **fully completed operations**, not partial successes.
|
|
64
|
+
An operation is counted as successful only when BOTH the event publish
|
|
65
|
+
AND the marker update succeed. This is intentional for exactly-once
|
|
66
|
+
semantics from the system's perspective.
|
|
67
|
+
|
|
68
|
+
If event publish succeeds but marker update fails:
|
|
69
|
+
- The counter is NOT incremented (operation treated as failed)
|
|
70
|
+
- The event WAS published to Kafka (at-least-once delivery)
|
|
71
|
+
- The entity will be re-processed on next tick (marker still NULL)
|
|
72
|
+
- Downstream consumers should deduplicate by event_id if needed
|
|
73
|
+
|
|
74
|
+
This atomic counting ensures that `markers_updated` always equals
|
|
75
|
+
`ack_timeouts_emitted + liveness_expirations_emitted` for successful
|
|
76
|
+
operations, making monitoring and alerting straightforward.
|
|
77
|
+
|
|
78
|
+
Attributes:
|
|
79
|
+
ack_timeouts_emitted: Number of ack timeout operations fully completed
|
|
80
|
+
(event published AND marker updated). Does not count partial
|
|
81
|
+
successes where publish succeeded but marker update failed.
|
|
82
|
+
liveness_expirations_emitted: Number of liveness expiry operations
|
|
83
|
+
fully completed (event published AND marker updated).
|
|
84
|
+
markers_updated: Number of projection markers successfully updated.
|
|
85
|
+
Always equals ack_timeouts_emitted + liveness_expirations_emitted
|
|
86
|
+
for successful operations.
|
|
87
|
+
errors: Tuple of error messages for failed emissions (immutable for
|
|
88
|
+
thread safety). Each error includes the node_id and reason for
|
|
89
|
+
failure. Note: an error may indicate the event was published but
|
|
90
|
+
marker update failed.
|
|
91
|
+
processing_time_ms: Total processing time in milliseconds.
|
|
92
|
+
tick_id: The RuntimeTick ID that triggered this processing.
|
|
93
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
>>> result = await emitter.process_timeouts(now=tick.now, tick_id=tick.tick_id)
|
|
97
|
+
>>> print(f"Emitted {result.ack_timeouts_emitted} ack timeouts")
|
|
98
|
+
>>> if result.errors:
|
|
99
|
+
... print(f"Errors: {result.errors}")
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
model_config = ConfigDict(
|
|
103
|
+
frozen=True,
|
|
104
|
+
extra="forbid",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
ack_timeouts_emitted: int = Field(
|
|
108
|
+
default=0,
|
|
109
|
+
ge=0,
|
|
110
|
+
description="Number of ack timeout operations fully completed (publish + marker update)",
|
|
111
|
+
)
|
|
112
|
+
liveness_expirations_emitted: int = Field(
|
|
113
|
+
default=0,
|
|
114
|
+
ge=0,
|
|
115
|
+
description="Number of liveness expiry operations fully completed (publish + marker update)",
|
|
116
|
+
)
|
|
117
|
+
markers_updated: int = Field(
|
|
118
|
+
default=0,
|
|
119
|
+
ge=0,
|
|
120
|
+
description="Number of projection markers successfully updated (equals sum of emitted counts)",
|
|
121
|
+
)
|
|
122
|
+
errors: tuple[str, ...] = Field(
|
|
123
|
+
default=(),
|
|
124
|
+
description="Tuple of error messages for failed emissions (immutable for thread safety)",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
@field_validator("errors", mode="before")
|
|
128
|
+
@classmethod
|
|
129
|
+
def _coerce_errors_to_tuple(cls, v: object) -> tuple[str, ...]:
|
|
130
|
+
"""Convert list/sequence to tuple for immutability.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
v: The input value to coerce.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
A tuple of error strings.
|
|
137
|
+
|
|
138
|
+
Raises:
|
|
139
|
+
ValueError: If input is not a valid sequence type.
|
|
140
|
+
"""
|
|
141
|
+
# NOTE: isinstance checks validate runtime type, but mypy cannot narrow
|
|
142
|
+
# the generic Sequence type to tuple[str, ...] in this validator context.
|
|
143
|
+
if isinstance(v, tuple):
|
|
144
|
+
return v # type: ignore[return-value] # NOTE: runtime type validated above
|
|
145
|
+
if isinstance(v, Sequence) and not isinstance(v, str | bytes):
|
|
146
|
+
return tuple(v) # type: ignore[return-value] # NOTE: runtime type validated above
|
|
147
|
+
raise ValueError(
|
|
148
|
+
f"errors must be a tuple or Sequence (excluding str/bytes), "
|
|
149
|
+
f"got {type(v).__name__}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
processing_time_ms: float = Field(
|
|
153
|
+
...,
|
|
154
|
+
ge=0.0,
|
|
155
|
+
description="Total processing time in milliseconds",
|
|
156
|
+
)
|
|
157
|
+
tick_id: UUID = Field(
|
|
158
|
+
...,
|
|
159
|
+
description="The RuntimeTick ID that triggered this processing",
|
|
160
|
+
)
|
|
161
|
+
correlation_id: UUID = Field(
|
|
162
|
+
...,
|
|
163
|
+
description="Correlation ID for distributed tracing",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def total_emitted(self) -> int:
|
|
168
|
+
"""Return total number of events emitted."""
|
|
169
|
+
return self.ack_timeouts_emitted + self.liveness_expirations_emitted
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def has_errors(self) -> bool:
|
|
173
|
+
"""Check if any errors occurred during processing."""
|
|
174
|
+
return len(self.errors) > 0
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class ModelTimeoutEmissionConfig(BaseModel):
|
|
178
|
+
"""Configuration for TimeoutEmitter.
|
|
179
|
+
|
|
180
|
+
Encapsulates configuration parameters for timeout emission processing,
|
|
181
|
+
including environment and namespace for topic routing.
|
|
182
|
+
|
|
183
|
+
Attributes:
|
|
184
|
+
environment: Environment identifier for topic routing (e.g., "local", "dev", "prod").
|
|
185
|
+
namespace: Namespace for topic routing (e.g., "onex", "myapp").
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
189
|
+
|
|
190
|
+
environment: str = Field(
|
|
191
|
+
default="local",
|
|
192
|
+
description="Environment for topic routing",
|
|
193
|
+
)
|
|
194
|
+
namespace: str = Field(
|
|
195
|
+
default="onex",
|
|
196
|
+
description="Namespace for topic routing",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class ServiceTimeoutEmitter:
|
|
201
|
+
"""Emitter for timeout events with emission marker updates.
|
|
202
|
+
|
|
203
|
+
Ensures restart-safe, exactly-once timeout event emission by:
|
|
204
|
+
1. Only processing entities without emission markers
|
|
205
|
+
2. Updating markers atomically after event emission
|
|
206
|
+
3. Using correlation_id from RuntimeTick for tracing
|
|
207
|
+
|
|
208
|
+
The emission pattern guarantees:
|
|
209
|
+
- Events are emitted BEFORE markers are updated (event-first semantics)
|
|
210
|
+
- If emit succeeds but marker fails, event is duplicated on retry
|
|
211
|
+
(at-least-once delivery, deduplicated by downstream consumers)
|
|
212
|
+
- If emit fails, marker stays NULL and will be retried on next tick
|
|
213
|
+
|
|
214
|
+
Design Note:
|
|
215
|
+
This emitter does NOT implement circuit breaker - it delegates to
|
|
216
|
+
the underlying event_bus and projector which have their own circuit
|
|
217
|
+
breaker implementations.
|
|
218
|
+
|
|
219
|
+
Usage:
|
|
220
|
+
>>> emitter = ServiceTimeoutEmitter(
|
|
221
|
+
... container=container,
|
|
222
|
+
... timeout_query=timeout_scanner,
|
|
223
|
+
... event_bus=event_bus,
|
|
224
|
+
... projector=projector,
|
|
225
|
+
... config=ModelTimeoutEmissionConfig(environment="dev", namespace="myapp"),
|
|
226
|
+
... )
|
|
227
|
+
>>> result = await emitter.process_timeouts(
|
|
228
|
+
... now=tick.now,
|
|
229
|
+
... tick_id=tick.tick_id,
|
|
230
|
+
... correlation_id=tick.correlation_id,
|
|
231
|
+
... )
|
|
232
|
+
|
|
233
|
+
Raises:
|
|
234
|
+
InfraConnectionError: If database or Kafka connection fails
|
|
235
|
+
InfraTimeoutError: If operations time out
|
|
236
|
+
InfraUnavailableError: If circuit breaker is open
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
# Default topic patterns following ONEX conventions
|
|
240
|
+
DEFAULT_ACK_TIMEOUT_TOPIC = (
|
|
241
|
+
"{env}.{namespace}.onex.evt.node-registration-ack-timed-out.v1"
|
|
242
|
+
)
|
|
243
|
+
DEFAULT_LIVENESS_EXPIRED_TOPIC = (
|
|
244
|
+
"{env}.{namespace}.onex.evt.node-liveness-expired.v1"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# Error rate threshold for systemic issue detection.
|
|
248
|
+
# When more than 50% of emissions fail in a single batch, this indicates
|
|
249
|
+
# a likely systemic issue (e.g., Kafka unavailable, database down) rather
|
|
250
|
+
# than isolated entity-specific failures. This threshold was chosen because:
|
|
251
|
+
#
|
|
252
|
+
# 1. Low false positive rate: Individual entity failures (e.g., validation
|
|
253
|
+
# errors) typically affect <10% of entities, so 50% clearly indicates
|
|
254
|
+
# infrastructure problems.
|
|
255
|
+
#
|
|
256
|
+
# 2. Early detection: 50% is high enough to avoid noise but low enough to
|
|
257
|
+
# catch issues before the entire batch fails.
|
|
258
|
+
#
|
|
259
|
+
# 3. Operator actionability: At 50%+, operators should investigate the
|
|
260
|
+
# underlying infrastructure rather than individual entities.
|
|
261
|
+
#
|
|
262
|
+
# This threshold triggers an ERROR-level log for alerting and monitoring.
|
|
263
|
+
ERROR_RATE_THRESHOLD: float = 0.5
|
|
264
|
+
|
|
265
|
+
def __init__(
|
|
266
|
+
self,
|
|
267
|
+
container: ModelONEXContainer,
|
|
268
|
+
timeout_query: ServiceTimeoutScanner,
|
|
269
|
+
event_bus: ProtocolEventBus,
|
|
270
|
+
projector: ProjectorShell,
|
|
271
|
+
config: ModelTimeoutEmissionConfig | None = None,
|
|
272
|
+
) -> None:
|
|
273
|
+
"""Initialize with required dependencies.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
container: ONEX container for dependency injection.
|
|
277
|
+
timeout_query: Scanner for querying overdue entities.
|
|
278
|
+
Must be initialized with a ProjectionReaderRegistration.
|
|
279
|
+
event_bus: Event bus for publishing timeout events.
|
|
280
|
+
Must implement ProtocolEventBus (publish_envelope method).
|
|
281
|
+
projector: ProjectorShell for updating emission markers.
|
|
282
|
+
Should be loaded from the registration projector contract.
|
|
283
|
+
config: Configuration for environment and namespace.
|
|
284
|
+
Defaults to ModelTimeoutEmissionConfig() if not provided.
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
>>> reader = ProjectionReaderRegistration(pool)
|
|
288
|
+
>>> timeout_query = ServiceTimeoutScanner(container, reader)
|
|
289
|
+
>>> bus = EventBusKafka.default()
|
|
290
|
+
>>> projector = projector_loader.load("registration_projector")
|
|
291
|
+
>>> emitter = ServiceTimeoutEmitter(
|
|
292
|
+
... container=container,
|
|
293
|
+
... timeout_query=timeout_query,
|
|
294
|
+
... event_bus=bus,
|
|
295
|
+
... projector=projector,
|
|
296
|
+
... config=ModelTimeoutEmissionConfig(environment="dev"),
|
|
297
|
+
... )
|
|
298
|
+
"""
|
|
299
|
+
self._container = container
|
|
300
|
+
self._timeout_query = timeout_query
|
|
301
|
+
self._event_bus = event_bus
|
|
302
|
+
self._projector = projector
|
|
303
|
+
self._config = config or ModelTimeoutEmissionConfig()
|
|
304
|
+
|
|
305
|
+
@property
|
|
306
|
+
def environment(self) -> str:
|
|
307
|
+
"""Return configured environment."""
|
|
308
|
+
return self._config.environment
|
|
309
|
+
|
|
310
|
+
@property
|
|
311
|
+
def namespace(self) -> str:
|
|
312
|
+
"""Return configured namespace."""
|
|
313
|
+
return self._config.namespace
|
|
314
|
+
|
|
315
|
+
def _build_topic(self, topic_pattern: str) -> str:
|
|
316
|
+
"""Build topic name from pattern with environment and namespace.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
topic_pattern: Topic pattern with {env} and {namespace} placeholders.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
Fully qualified topic name.
|
|
323
|
+
"""
|
|
324
|
+
return topic_pattern.format(
|
|
325
|
+
env=self._config.environment,
|
|
326
|
+
namespace=self._config.namespace,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
async def process_timeouts(
|
|
330
|
+
self,
|
|
331
|
+
now: datetime,
|
|
332
|
+
tick_id: UUID,
|
|
333
|
+
correlation_id: UUID,
|
|
334
|
+
domain: str = "registration",
|
|
335
|
+
) -> ModelTimeoutEmissionResult:
|
|
336
|
+
"""Process all pending timeouts.
|
|
337
|
+
|
|
338
|
+
Queries for overdue entities, emits timeout events for each,
|
|
339
|
+
and updates emission markers to prevent duplicate emissions.
|
|
340
|
+
|
|
341
|
+
The processing order is:
|
|
342
|
+
1. Query for overdue ack and liveness entities
|
|
343
|
+
2. For each ack timeout: emit event, then update marker
|
|
344
|
+
3. For each liveness expiration: emit event, then update marker
|
|
345
|
+
4. Capture any errors but continue processing remaining entities
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
now: Injected current time from RuntimeTick. This is the
|
|
349
|
+
deterministic time used for detecting overdue entities.
|
|
350
|
+
tick_id: RuntimeTick ID (becomes causation_id for emitted events).
|
|
351
|
+
Links emitted events to the tick that triggered them.
|
|
352
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
353
|
+
Propagated to all emitted events.
|
|
354
|
+
domain: Domain namespace for topic routing. Defaults to "registration".
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
ModelTimeoutEmissionResult with counts and any errors.
|
|
358
|
+
Errors are captured but do not stop processing of remaining entities.
|
|
359
|
+
|
|
360
|
+
Raises:
|
|
361
|
+
InfraConnectionError: If database or Kafka connection fails during query
|
|
362
|
+
InfraTimeoutError: If query or emit operations time out
|
|
363
|
+
InfraUnavailableError: If circuit breaker is open
|
|
364
|
+
|
|
365
|
+
Example:
|
|
366
|
+
>>> result = await emitter.process_timeouts(
|
|
367
|
+
... now=datetime.now(UTC),
|
|
368
|
+
... tick_id=uuid4(),
|
|
369
|
+
... correlation_id=uuid4(),
|
|
370
|
+
... )
|
|
371
|
+
>>> print(f"Emitted {result.total_emitted} timeout events")
|
|
372
|
+
"""
|
|
373
|
+
start_time = time.perf_counter()
|
|
374
|
+
errors: list[str] = []
|
|
375
|
+
ack_emitted = 0
|
|
376
|
+
liveness_emitted = 0
|
|
377
|
+
markers_updated = 0
|
|
378
|
+
|
|
379
|
+
logger.debug(
|
|
380
|
+
"Processing timeouts",
|
|
381
|
+
extra={
|
|
382
|
+
"now": now.isoformat(),
|
|
383
|
+
"tick_id": str(tick_id),
|
|
384
|
+
"correlation_id": str(correlation_id),
|
|
385
|
+
"domain": domain,
|
|
386
|
+
},
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
# Query for overdue entities
|
|
390
|
+
query_result = await self._timeout_query.find_overdue_entities(
|
|
391
|
+
now=now,
|
|
392
|
+
domain=domain,
|
|
393
|
+
correlation_id=correlation_id,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
logger.debug(
|
|
397
|
+
"Found overdue entities",
|
|
398
|
+
extra={
|
|
399
|
+
"ack_timeout_count": len(query_result.ack_timeouts),
|
|
400
|
+
"liveness_expiration_count": len(query_result.liveness_expirations),
|
|
401
|
+
"correlation_id": str(correlation_id),
|
|
402
|
+
},
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# Process ack timeouts
|
|
406
|
+
for projection in query_result.ack_timeouts:
|
|
407
|
+
try:
|
|
408
|
+
await self._emit_ack_timeout(
|
|
409
|
+
projection=projection,
|
|
410
|
+
detected_at=now,
|
|
411
|
+
tick_id=tick_id,
|
|
412
|
+
correlation_id=correlation_id,
|
|
413
|
+
)
|
|
414
|
+
# Counters increment ONLY after full operation succeeds (publish + marker).
|
|
415
|
+
# If marker update fails, _emit_ack_timeout raises and we skip these lines.
|
|
416
|
+
# See ModelTimeoutEmissionResult docstring for counter semantics.
|
|
417
|
+
ack_emitted += 1
|
|
418
|
+
markers_updated += 1
|
|
419
|
+
except Exception as e:
|
|
420
|
+
error_msg = (
|
|
421
|
+
f"ack_timeout failed for node {projection.entity_id}: "
|
|
422
|
+
f"{type(e).__name__}"
|
|
423
|
+
)
|
|
424
|
+
errors.append(error_msg)
|
|
425
|
+
logger.warning(
|
|
426
|
+
error_msg,
|
|
427
|
+
extra={
|
|
428
|
+
"node_id": str(projection.entity_id),
|
|
429
|
+
"correlation_id": str(correlation_id),
|
|
430
|
+
"error_type": type(e).__name__,
|
|
431
|
+
},
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
# Process liveness expirations
|
|
435
|
+
for projection in query_result.liveness_expirations:
|
|
436
|
+
try:
|
|
437
|
+
await self._emit_liveness_expiration(
|
|
438
|
+
projection=projection,
|
|
439
|
+
detected_at=now,
|
|
440
|
+
tick_id=tick_id,
|
|
441
|
+
correlation_id=correlation_id,
|
|
442
|
+
)
|
|
443
|
+
# Counters increment ONLY after full operation succeeds (publish + marker).
|
|
444
|
+
# If marker update fails, _emit_liveness_expiration raises and we skip these lines.
|
|
445
|
+
# See ModelTimeoutEmissionResult docstring for counter semantics.
|
|
446
|
+
liveness_emitted += 1
|
|
447
|
+
markers_updated += 1
|
|
448
|
+
except Exception as e:
|
|
449
|
+
error_msg = (
|
|
450
|
+
f"liveness_expiration failed for node {projection.entity_id}: "
|
|
451
|
+
f"{type(e).__name__}"
|
|
452
|
+
)
|
|
453
|
+
errors.append(error_msg)
|
|
454
|
+
logger.warning(
|
|
455
|
+
error_msg,
|
|
456
|
+
extra={
|
|
457
|
+
"node_id": str(projection.entity_id),
|
|
458
|
+
"correlation_id": str(correlation_id),
|
|
459
|
+
"error_type": type(e).__name__,
|
|
460
|
+
},
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
# Check error rate for systemic issue detection.
|
|
464
|
+
# See ERROR_RATE_THRESHOLD documentation for threshold rationale.
|
|
465
|
+
total_attempted = len(query_result.ack_timeouts) + len(
|
|
466
|
+
query_result.liveness_expirations
|
|
467
|
+
)
|
|
468
|
+
if total_attempted > 0:
|
|
469
|
+
error_rate = len(errors) / total_attempted
|
|
470
|
+
if error_rate > self.ERROR_RATE_THRESHOLD:
|
|
471
|
+
logger.error(
|
|
472
|
+
"High timeout emission failure rate - possible systemic issue",
|
|
473
|
+
extra={
|
|
474
|
+
"error_rate": error_rate,
|
|
475
|
+
"error_rate_threshold": self.ERROR_RATE_THRESHOLD,
|
|
476
|
+
"total_attempted": total_attempted,
|
|
477
|
+
"error_count": len(errors),
|
|
478
|
+
"correlation_id": str(correlation_id),
|
|
479
|
+
},
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
end_time = time.perf_counter()
|
|
483
|
+
duration_ms = (end_time - start_time) * 1000.0
|
|
484
|
+
|
|
485
|
+
logger.info(
|
|
486
|
+
"Timeout processing completed",
|
|
487
|
+
extra={
|
|
488
|
+
"ack_timeouts_emitted": ack_emitted,
|
|
489
|
+
"liveness_expirations_emitted": liveness_emitted,
|
|
490
|
+
"markers_updated": markers_updated,
|
|
491
|
+
"error_count": len(errors),
|
|
492
|
+
"processing_time_ms": duration_ms,
|
|
493
|
+
"correlation_id": str(correlation_id),
|
|
494
|
+
},
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
return ModelTimeoutEmissionResult(
|
|
498
|
+
ack_timeouts_emitted=ack_emitted,
|
|
499
|
+
liveness_expirations_emitted=liveness_emitted,
|
|
500
|
+
markers_updated=markers_updated,
|
|
501
|
+
errors=errors,
|
|
502
|
+
processing_time_ms=duration_ms,
|
|
503
|
+
tick_id=tick_id,
|
|
504
|
+
correlation_id=correlation_id,
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
async def _emit_ack_timeout(
|
|
508
|
+
self,
|
|
509
|
+
projection: ModelRegistrationProjection,
|
|
510
|
+
detected_at: datetime,
|
|
511
|
+
tick_id: UUID,
|
|
512
|
+
correlation_id: UUID,
|
|
513
|
+
) -> None:
|
|
514
|
+
"""Emit ack timeout event and update marker.
|
|
515
|
+
|
|
516
|
+
This method follows the event-first pattern:
|
|
517
|
+
1. Create and emit the timeout event
|
|
518
|
+
2. Update the emission marker in projection atomically
|
|
519
|
+
|
|
520
|
+
If the emit succeeds but marker update fails, the event will be
|
|
521
|
+
duplicated on retry (at-least-once semantics). Downstream consumers
|
|
522
|
+
should deduplicate by event_id if needed.
|
|
523
|
+
|
|
524
|
+
Args:
|
|
525
|
+
projection: The projection for the node that timed out.
|
|
526
|
+
detected_at: When the timeout was detected (from RuntimeTick.now).
|
|
527
|
+
tick_id: RuntimeTick ID (becomes causation_id for the event).
|
|
528
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
529
|
+
|
|
530
|
+
Raises:
|
|
531
|
+
ProtocolConfigurationError: If ack_deadline is None (invalid projection state)
|
|
532
|
+
InfraConnectionError: If Kafka connection fails
|
|
533
|
+
InfraTimeoutError: If publish times out
|
|
534
|
+
InfraUnavailableError: If circuit breaker is open
|
|
535
|
+
RuntimeHostError: For other database errors
|
|
536
|
+
"""
|
|
537
|
+
# Validate ack_deadline exists (should always be present for timeout candidates)
|
|
538
|
+
if projection.ack_deadline is None:
|
|
539
|
+
raise ProtocolConfigurationError(
|
|
540
|
+
f"Cannot emit ack timeout for node {projection.entity_id}: "
|
|
541
|
+
"ack_deadline is None",
|
|
542
|
+
context=ModelInfraErrorContext(
|
|
543
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
544
|
+
operation="emit_ack_timeout",
|
|
545
|
+
target_name="registration_projection",
|
|
546
|
+
correlation_id=correlation_id,
|
|
547
|
+
),
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# Runtime import to avoid circular import (see TYPE_CHECKING block)
|
|
551
|
+
from omnibase_infra.models.registration.events.model_node_registration_ack_timed_out import (
|
|
552
|
+
ModelNodeRegistrationAckTimedOut,
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
# 1. Create event
|
|
556
|
+
event = ModelNodeRegistrationAckTimedOut(
|
|
557
|
+
entity_id=projection.entity_id,
|
|
558
|
+
node_id=projection.entity_id,
|
|
559
|
+
correlation_id=correlation_id,
|
|
560
|
+
causation_id=tick_id,
|
|
561
|
+
emitted_at=detected_at,
|
|
562
|
+
deadline_at=projection.ack_deadline,
|
|
563
|
+
previous_state=projection.current_state,
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
# 2. Build topic and publish event
|
|
567
|
+
topic = self._build_topic(self.DEFAULT_ACK_TIMEOUT_TOPIC)
|
|
568
|
+
|
|
569
|
+
logger.debug(
|
|
570
|
+
"Emitting ack timeout event",
|
|
571
|
+
extra={
|
|
572
|
+
"node_id": str(projection.entity_id),
|
|
573
|
+
"topic": topic,
|
|
574
|
+
"correlation_id": str(correlation_id),
|
|
575
|
+
},
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
# Wrap event in ModelEventEnvelope for protocol compliance
|
|
579
|
+
envelope: ModelEventEnvelope[object] = ModelEventEnvelope(
|
|
580
|
+
payload=event,
|
|
581
|
+
correlation_id=correlation_id,
|
|
582
|
+
)
|
|
583
|
+
await self._event_bus.publish_envelope(
|
|
584
|
+
envelope=envelope, # type: ignore[arg-type]
|
|
585
|
+
topic=topic,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
# 3. Update emission marker atomically
|
|
589
|
+
# This MUST happen AFTER successful publish to ensure exactly-once semantics
|
|
590
|
+
# Uses atomic marker update to avoid race conditions with concurrent updates
|
|
591
|
+
await self._projector.partial_update(
|
|
592
|
+
aggregate_id=projection.entity_id,
|
|
593
|
+
updates={
|
|
594
|
+
"ack_timeout_emitted_at": detected_at,
|
|
595
|
+
"updated_at": detected_at,
|
|
596
|
+
},
|
|
597
|
+
correlation_id=correlation_id,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
async def _emit_liveness_expiration(
|
|
601
|
+
self,
|
|
602
|
+
projection: ModelRegistrationProjection,
|
|
603
|
+
detected_at: datetime,
|
|
604
|
+
tick_id: UUID,
|
|
605
|
+
correlation_id: UUID,
|
|
606
|
+
) -> None:
|
|
607
|
+
"""Emit liveness expiration event and update marker.
|
|
608
|
+
|
|
609
|
+
This method follows the event-first pattern:
|
|
610
|
+
1. Create and emit the expiration event
|
|
611
|
+
2. Update the emission marker in projection atomically
|
|
612
|
+
|
|
613
|
+
If the emit succeeds but marker update fails, the event will be
|
|
614
|
+
duplicated on retry (at-least-once semantics). Downstream consumers
|
|
615
|
+
should deduplicate by event_id if needed.
|
|
616
|
+
|
|
617
|
+
Args:
|
|
618
|
+
projection: The projection for the node whose liveness expired.
|
|
619
|
+
detected_at: When the expiration was detected (from RuntimeTick.now).
|
|
620
|
+
tick_id: RuntimeTick ID (becomes causation_id for the event).
|
|
621
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
622
|
+
|
|
623
|
+
Raises:
|
|
624
|
+
ProtocolConfigurationError: If liveness_deadline is None (invalid projection state)
|
|
625
|
+
InfraConnectionError: If Kafka connection fails
|
|
626
|
+
InfraTimeoutError: If publish times out
|
|
627
|
+
InfraUnavailableError: If circuit breaker is open
|
|
628
|
+
RuntimeHostError: For other database errors
|
|
629
|
+
"""
|
|
630
|
+
# Validate liveness_deadline exists
|
|
631
|
+
if projection.liveness_deadline is None:
|
|
632
|
+
raise ProtocolConfigurationError(
|
|
633
|
+
f"Cannot emit liveness expiration for node {projection.entity_id}: "
|
|
634
|
+
"liveness_deadline is None",
|
|
635
|
+
context=ModelInfraErrorContext(
|
|
636
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
637
|
+
operation="emit_liveness_expiration",
|
|
638
|
+
target_name="registration_projection",
|
|
639
|
+
correlation_id=correlation_id,
|
|
640
|
+
),
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
# Runtime import to avoid circular import (see TYPE_CHECKING block)
|
|
644
|
+
from omnibase_infra.nodes.node_registration_orchestrator.models.model_node_liveness_expired import (
|
|
645
|
+
ModelNodeLivenessExpired,
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
# 1. Create event
|
|
649
|
+
# last_heartbeat_at: None if no heartbeats were ever received.
|
|
650
|
+
# The projection tracks this field explicitly.
|
|
651
|
+
event = ModelNodeLivenessExpired(
|
|
652
|
+
node_id=projection.entity_id,
|
|
653
|
+
liveness_deadline=projection.liveness_deadline,
|
|
654
|
+
detected_at=detected_at,
|
|
655
|
+
last_heartbeat_at=projection.last_heartbeat_at,
|
|
656
|
+
correlation_id=correlation_id,
|
|
657
|
+
causation_id=tick_id,
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
# 2. Build topic and publish event
|
|
661
|
+
topic = self._build_topic(self.DEFAULT_LIVENESS_EXPIRED_TOPIC)
|
|
662
|
+
|
|
663
|
+
logger.debug(
|
|
664
|
+
"Emitting liveness expiration event",
|
|
665
|
+
extra={
|
|
666
|
+
"node_id": str(projection.entity_id),
|
|
667
|
+
"topic": topic,
|
|
668
|
+
"correlation_id": str(correlation_id),
|
|
669
|
+
},
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
# Wrap event in ModelEventEnvelope for protocol compliance
|
|
673
|
+
envelope: ModelEventEnvelope[object] = ModelEventEnvelope(
|
|
674
|
+
payload=event,
|
|
675
|
+
correlation_id=correlation_id,
|
|
676
|
+
)
|
|
677
|
+
await self._event_bus.publish_envelope(
|
|
678
|
+
envelope=envelope, # type: ignore[arg-type]
|
|
679
|
+
topic=topic,
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
# 3. Update emission marker atomically
|
|
683
|
+
# This MUST happen AFTER successful publish to ensure exactly-once semantics
|
|
684
|
+
# Uses atomic marker update to avoid race conditions with concurrent updates
|
|
685
|
+
await self._projector.partial_update(
|
|
686
|
+
aggregate_id=projection.entity_id,
|
|
687
|
+
updates={
|
|
688
|
+
"liveness_timeout_emitted_at": detected_at,
|
|
689
|
+
"updated_at": detected_at,
|
|
690
|
+
},
|
|
691
|
+
correlation_id=correlation_id,
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
__all__: list[str] = [
|
|
696
|
+
"ModelTimeoutEmissionConfig",
|
|
697
|
+
"ModelTimeoutEmissionResult",
|
|
698
|
+
"ServiceTimeoutEmitter",
|
|
699
|
+
]
|