omnibase_infra 0.2.2__py3-none-any.whl → 0.2.4__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 +1 -1
- omnibase_infra/adapters/adapter_onex_tool_execution.py +6 -1
- 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/contracts/handlers/filesystem/handler_contract.yaml +1 -1
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +1 -1
- omnibase_infra/enums/__init__.py +6 -0
- omnibase_infra/enums/enum_handler_error_type.py +10 -0
- omnibase_infra/enums/enum_handler_source_mode.py +72 -0
- omnibase_infra/enums/enum_kafka_acks.py +99 -0
- omnibase_infra/event_bus/event_bus_kafka.py +1 -1
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +59 -10
- omnibase_infra/handlers/__init__.py +8 -1
- omnibase_infra/handlers/handler_consul.py +7 -1
- omnibase_infra/handlers/handler_db.py +8 -2
- omnibase_infra/handlers/handler_graph.py +860 -4
- omnibase_infra/handlers/handler_http.py +8 -2
- omnibase_infra/handlers/handler_intent.py +387 -0
- omnibase_infra/handlers/handler_mcp.py +10 -1
- omnibase_infra/handlers/handler_vault.py +11 -5
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +7 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +7 -0
- omnibase_infra/mixins/mixin_node_introspection.py +18 -0
- omnibase_infra/models/discovery/model_introspection_config.py +11 -0
- omnibase_infra/models/handlers/__init__.py +38 -5
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +4 -4
- omnibase_infra/models/handlers/model_contract_discovery_result.py +6 -4
- omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +9 -0
- omnibase_infra/models/runtime/model_handler_contract.py +25 -9
- omnibase_infra/models/runtime/model_loaded_handler.py +9 -0
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +1 -1
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +7 -7
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +4 -3
- omnibase_infra/nodes/node_registration_storage_effect/node.py +4 -1
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +1 -1
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +4 -1
- omnibase_infra/protocols/__init__.py +2 -0
- omnibase_infra/protocols/protocol_container_aware.py +200 -0
- omnibase_infra/runtime/__init__.py +39 -0
- omnibase_infra/runtime/handler_bootstrap_source.py +26 -33
- omnibase_infra/runtime/handler_contract_config_loader.py +1 -1
- omnibase_infra/runtime/handler_contract_source.py +10 -51
- omnibase_infra/runtime/handler_identity.py +81 -0
- omnibase_infra/runtime/handler_plugin_loader.py +15 -0
- omnibase_infra/runtime/handler_registry.py +11 -3
- omnibase_infra/runtime/handler_source_resolver.py +326 -0
- omnibase_infra/runtime/protocol_lifecycle_executor.py +6 -6
- omnibase_infra/runtime/registry/registry_protocol_binding.py +13 -13
- omnibase_infra/runtime/registry_contract_source.py +693 -0
- omnibase_infra/runtime/service_kernel.py +1 -1
- omnibase_infra/runtime/service_runtime_host_process.py +463 -190
- omnibase_infra/runtime/util_wiring.py +12 -3
- omnibase_infra/services/__init__.py +21 -0
- omnibase_infra/services/corpus_capture.py +7 -1
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +9 -3
- omnibase_infra/services/registry_api/main.py +31 -13
- omnibase_infra/services/registry_api/service.py +10 -19
- omnibase_infra/services/service_timeout_emitter.py +7 -1
- omnibase_infra/services/service_timeout_scanner.py +7 -3
- omnibase_infra/services/session/__init__.py +56 -0
- omnibase_infra/services/session/config_consumer.py +120 -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/utils/__init__.py +19 -0
- omnibase_infra/utils/util_atomic_file.py +261 -0
- omnibase_infra/utils/util_db_transaction.py +239 -0
- omnibase_infra/utils/util_retry_optimistic.py +281 -0
- omnibase_infra/validation/__init__.py +16 -0
- omnibase_infra/validation/validation_exemptions.yaml +27 -0
- {omnibase_infra-0.2.2.dist-info → omnibase_infra-0.2.4.dist-info}/METADATA +3 -3
- {omnibase_infra-0.2.2.dist-info → omnibase_infra-0.2.4.dist-info}/RECORD +79 -58
- {omnibase_infra-0.2.2.dist-info → omnibase_infra-0.2.4.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.2.dist-info → omnibase_infra-0.2.4.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.2.dist-info → omnibase_infra-0.2.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Handler Source Resolver for Multi-Source Handler Discovery.
|
|
4
|
+
|
|
5
|
+
This module provides the HandlerSourceResolver class, which resolves handlers
|
|
6
|
+
from multiple sources (bootstrap, contract) based on the configured mode.
|
|
7
|
+
|
|
8
|
+
Part of OMN-1095: Handler Source Mode Hybrid Resolution.
|
|
9
|
+
|
|
10
|
+
Resolution Modes:
|
|
11
|
+
- BOOTSTRAP: Only use hardcoded bootstrap handlers.
|
|
12
|
+
- CONTRACT: Only use YAML contract-discovered handlers.
|
|
13
|
+
- HYBRID: Per-handler resolution with configurable precedence.
|
|
14
|
+
|
|
15
|
+
In HYBRID mode, the resolver performs per-handler identity resolution:
|
|
16
|
+
1. Discovers handlers from both bootstrap and contract sources
|
|
17
|
+
2. Builds a handler map keyed by handler_id
|
|
18
|
+
3. Resolves conflicts based on allow_bootstrap_override:
|
|
19
|
+
- False (default): Contract handlers override bootstrap handlers
|
|
20
|
+
- True: Bootstrap handlers override contract handlers
|
|
21
|
+
4. Non-conflicting handlers are included from both sources
|
|
22
|
+
|
|
23
|
+
See Also:
|
|
24
|
+
- EnumHandlerSourceMode: Defines the resolution modes
|
|
25
|
+
- HandlerBootstrapSource: Provides bootstrap handlers
|
|
26
|
+
- HandlerContractSource: Provides contract-discovered handlers
|
|
27
|
+
- ProtocolContractSource: Protocol for handler sources
|
|
28
|
+
|
|
29
|
+
.. versionadded:: 0.7.0
|
|
30
|
+
Created as part of OMN-1095 handler source mode hybrid resolution.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import logging
|
|
36
|
+
from typing import TYPE_CHECKING
|
|
37
|
+
|
|
38
|
+
from omnibase_infra.enums.enum_handler_source_mode import EnumHandlerSourceMode
|
|
39
|
+
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from omnibase_infra.runtime.protocol_contract_source import ProtocolContractSource
|
|
42
|
+
|
|
43
|
+
# Import models after TYPE_CHECKING to avoid circular imports
|
|
44
|
+
from omnibase_infra.models.errors import ModelHandlerValidationError
|
|
45
|
+
from omnibase_infra.models.handlers import (
|
|
46
|
+
ModelContractDiscoveryResult,
|
|
47
|
+
ModelHandlerDescriptor,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Forward Reference Resolution:
|
|
51
|
+
# ModelContractDiscoveryResult uses a forward reference to ModelHandlerValidationError.
|
|
52
|
+
# Since we import ModelHandlerValidationError above, we can call model_rebuild() here
|
|
53
|
+
# to resolve the forward reference. This call is idempotent - multiple calls are harmless.
|
|
54
|
+
ModelContractDiscoveryResult.model_rebuild()
|
|
55
|
+
|
|
56
|
+
logger = logging.getLogger(__name__)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class HandlerSourceResolver:
|
|
60
|
+
"""Resolver for multi-source handler discovery with configurable modes.
|
|
61
|
+
|
|
62
|
+
This class resolves handlers from bootstrap and contract sources based on
|
|
63
|
+
the configured mode. It supports three resolution strategies:
|
|
64
|
+
|
|
65
|
+
- BOOTSTRAP: Use only bootstrap handlers, ignore contracts.
|
|
66
|
+
- CONTRACT: Use only contract handlers, ignore bootstrap.
|
|
67
|
+
- HYBRID: Per-handler resolution with configurable precedence:
|
|
68
|
+
- allow_bootstrap_override=False (default): Contract handlers take
|
|
69
|
+
precedence over bootstrap handlers with the same handler_id.
|
|
70
|
+
- allow_bootstrap_override=True: Bootstrap handlers take precedence
|
|
71
|
+
over contract handlers with the same handler_id.
|
|
72
|
+
In both cases, handlers without conflicts are included from both sources.
|
|
73
|
+
|
|
74
|
+
Attributes:
|
|
75
|
+
mode: The configured resolution mode.
|
|
76
|
+
allow_bootstrap_override: If True, bootstrap handlers take precedence
|
|
77
|
+
in HYBRID mode. Default is False (contract precedence).
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
>>> resolver = HandlerSourceResolver(
|
|
81
|
+
... bootstrap_source=bootstrap_source,
|
|
82
|
+
... contract_source=contract_source,
|
|
83
|
+
... mode=EnumHandlerSourceMode.HYBRID,
|
|
84
|
+
... )
|
|
85
|
+
>>> result = await resolver.resolve_handlers()
|
|
86
|
+
>>> print(f"Discovered {len(result.descriptors)} handlers")
|
|
87
|
+
|
|
88
|
+
.. versionadded:: 0.7.0
|
|
89
|
+
Created as part of OMN-1095 handler source mode hybrid resolution.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
bootstrap_source: ProtocolContractSource,
|
|
95
|
+
contract_source: ProtocolContractSource,
|
|
96
|
+
mode: EnumHandlerSourceMode,
|
|
97
|
+
*,
|
|
98
|
+
allow_bootstrap_override: bool = False,
|
|
99
|
+
) -> None:
|
|
100
|
+
"""Initialize the handler source resolver.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
bootstrap_source: Source for bootstrap handlers. Must implement
|
|
104
|
+
ProtocolContractSource with discover_handlers() method.
|
|
105
|
+
contract_source: Source for contract-discovered handlers. Must
|
|
106
|
+
implement ProtocolContractSource with discover_handlers() method.
|
|
107
|
+
mode: Resolution mode determining which sources are used and how
|
|
108
|
+
handlers are merged.
|
|
109
|
+
allow_bootstrap_override: If True, bootstrap handlers override
|
|
110
|
+
contract handlers with the same handler_id in HYBRID mode.
|
|
111
|
+
Default is False (contract handlers take precedence).
|
|
112
|
+
Has no effect in BOOTSTRAP or CONTRACT modes.
|
|
113
|
+
"""
|
|
114
|
+
self._bootstrap_source = bootstrap_source
|
|
115
|
+
self._contract_source = contract_source
|
|
116
|
+
self._mode = mode
|
|
117
|
+
self._allow_bootstrap_override = allow_bootstrap_override
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def mode(self) -> EnumHandlerSourceMode:
|
|
121
|
+
"""Get the configured resolution mode.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
EnumHandlerSourceMode: The mode used for handler resolution.
|
|
125
|
+
"""
|
|
126
|
+
return self._mode
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def allow_bootstrap_override(self) -> bool:
|
|
130
|
+
"""Get the bootstrap override configuration.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
bool: True if bootstrap handlers take precedence in HYBRID mode,
|
|
134
|
+
False if contract handlers take precedence (default).
|
|
135
|
+
"""
|
|
136
|
+
return self._allow_bootstrap_override
|
|
137
|
+
|
|
138
|
+
async def resolve_handlers(self) -> ModelContractDiscoveryResult:
|
|
139
|
+
"""Resolve handlers based on the configured mode.
|
|
140
|
+
|
|
141
|
+
Discovers handlers from the appropriate source(s) based on mode:
|
|
142
|
+
- BOOTSTRAP: Only queries bootstrap source
|
|
143
|
+
- CONTRACT: Only queries contract source
|
|
144
|
+
- HYBRID: Queries both sources and merges with contract precedence
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
ModelContractDiscoveryResult: Container with discovered descriptors
|
|
148
|
+
and any validation errors from the queried source(s).
|
|
149
|
+
"""
|
|
150
|
+
if self._mode == EnumHandlerSourceMode.BOOTSTRAP:
|
|
151
|
+
return await self._resolve_bootstrap()
|
|
152
|
+
elif self._mode == EnumHandlerSourceMode.CONTRACT:
|
|
153
|
+
return await self._resolve_contract()
|
|
154
|
+
else:
|
|
155
|
+
# HYBRID mode
|
|
156
|
+
return await self._resolve_hybrid()
|
|
157
|
+
|
|
158
|
+
async def _resolve_bootstrap(self) -> ModelContractDiscoveryResult:
|
|
159
|
+
"""Resolve handlers using only the bootstrap source.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
ModelContractDiscoveryResult: Handlers from bootstrap source only.
|
|
163
|
+
"""
|
|
164
|
+
result = await self._bootstrap_source.discover_handlers()
|
|
165
|
+
|
|
166
|
+
logger.info(
|
|
167
|
+
"Handler resolution completed (BOOTSTRAP mode)",
|
|
168
|
+
extra={
|
|
169
|
+
"mode": self._mode.value,
|
|
170
|
+
"bootstrap_handler_count": len(result.descriptors),
|
|
171
|
+
"resolved_handler_count": len(result.descriptors),
|
|
172
|
+
},
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return result
|
|
176
|
+
|
|
177
|
+
async def _resolve_contract(self) -> ModelContractDiscoveryResult:
|
|
178
|
+
"""Resolve handlers using only the contract source.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
ModelContractDiscoveryResult: Handlers from contract source only.
|
|
182
|
+
"""
|
|
183
|
+
result = await self._contract_source.discover_handlers()
|
|
184
|
+
|
|
185
|
+
logger.info(
|
|
186
|
+
"Handler resolution completed (CONTRACT mode)",
|
|
187
|
+
extra={
|
|
188
|
+
"mode": self._mode.value,
|
|
189
|
+
"contract_handler_count": len(result.descriptors),
|
|
190
|
+
"resolved_handler_count": len(result.descriptors),
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return result
|
|
195
|
+
|
|
196
|
+
async def _resolve_hybrid(self) -> ModelContractDiscoveryResult:
|
|
197
|
+
"""Resolve handlers using both sources with configurable precedence.
|
|
198
|
+
|
|
199
|
+
In HYBRID mode:
|
|
200
|
+
1. Discover handlers from both bootstrap and contract sources
|
|
201
|
+
2. Build a handler map keyed by handler_id
|
|
202
|
+
3. Resolve conflicts based on allow_bootstrap_override:
|
|
203
|
+
- False (default): Contract handlers override bootstrap handlers
|
|
204
|
+
- True: Bootstrap handlers override contract handlers
|
|
205
|
+
4. Non-conflicting handlers are included from both sources
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
ModelContractDiscoveryResult: Merged handlers with configured
|
|
209
|
+
precedence and combined validation errors from both sources.
|
|
210
|
+
"""
|
|
211
|
+
# Get handlers from both sources
|
|
212
|
+
bootstrap_result = await self._bootstrap_source.discover_handlers()
|
|
213
|
+
contract_result = await self._contract_source.discover_handlers()
|
|
214
|
+
|
|
215
|
+
# Build lookup maps for both sources
|
|
216
|
+
bootstrap_by_id: dict[str, ModelHandlerDescriptor] = {
|
|
217
|
+
d.handler_id: d for d in bootstrap_result.descriptors
|
|
218
|
+
}
|
|
219
|
+
contract_by_id: dict[str, ModelHandlerDescriptor] = {
|
|
220
|
+
d.handler_id: d for d in contract_result.descriptors
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# Determine which source takes precedence
|
|
224
|
+
if self._allow_bootstrap_override:
|
|
225
|
+
# Bootstrap wins conflicts: add bootstrap first, then contract fallbacks
|
|
226
|
+
primary_source = bootstrap_result.descriptors
|
|
227
|
+
primary_by_id = bootstrap_by_id
|
|
228
|
+
secondary_source = contract_result.descriptors
|
|
229
|
+
secondary_by_id = contract_by_id
|
|
230
|
+
primary_name = "bootstrap"
|
|
231
|
+
secondary_name = "contract"
|
|
232
|
+
else:
|
|
233
|
+
# Contract wins conflicts (default): add contract first, then bootstrap fallbacks
|
|
234
|
+
primary_source = contract_result.descriptors
|
|
235
|
+
primary_by_id = contract_by_id
|
|
236
|
+
secondary_source = bootstrap_result.descriptors
|
|
237
|
+
secondary_by_id = bootstrap_by_id
|
|
238
|
+
primary_name = "contract"
|
|
239
|
+
secondary_name = "bootstrap"
|
|
240
|
+
|
|
241
|
+
# Build handler map - primary source handlers first (they take precedence)
|
|
242
|
+
handlers_by_id: dict[str, ModelHandlerDescriptor] = {}
|
|
243
|
+
|
|
244
|
+
# Add primary handlers (they win conflicts)
|
|
245
|
+
for descriptor in primary_source:
|
|
246
|
+
handlers_by_id[descriptor.handler_id] = descriptor
|
|
247
|
+
|
|
248
|
+
# Log primary-only handlers (no secondary equivalent)
|
|
249
|
+
if descriptor.handler_id not in secondary_by_id:
|
|
250
|
+
logger.debug(
|
|
251
|
+
f"Adding {primary_name}-only handler (no {secondary_name} equivalent)",
|
|
252
|
+
extra={
|
|
253
|
+
"handler_id": descriptor.handler_id,
|
|
254
|
+
"handler_name": descriptor.name,
|
|
255
|
+
"source": primary_name,
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Add secondary handlers only if not already present (fallback)
|
|
260
|
+
fallback_count = 0
|
|
261
|
+
override_count = 0
|
|
262
|
+
for descriptor in secondary_source:
|
|
263
|
+
if descriptor.handler_id in handlers_by_id:
|
|
264
|
+
# Primary handler wins - this is an override
|
|
265
|
+
override_count += 1
|
|
266
|
+
primary_handler = handlers_by_id[descriptor.handler_id]
|
|
267
|
+
logger.debug(
|
|
268
|
+
f"{primary_name.capitalize()} handler overrides {secondary_name} handler",
|
|
269
|
+
extra={
|
|
270
|
+
"handler_id": descriptor.handler_id,
|
|
271
|
+
"primary_name": primary_handler.name,
|
|
272
|
+
"secondary_name": descriptor.name,
|
|
273
|
+
"primary_source": primary_name,
|
|
274
|
+
"secondary_source": secondary_name,
|
|
275
|
+
"contract_path": (
|
|
276
|
+
primary_handler.contract_path
|
|
277
|
+
if primary_name == "contract"
|
|
278
|
+
else descriptor.contract_path
|
|
279
|
+
),
|
|
280
|
+
},
|
|
281
|
+
)
|
|
282
|
+
else:
|
|
283
|
+
# No primary handler with this ID - use secondary as fallback
|
|
284
|
+
handlers_by_id[descriptor.handler_id] = descriptor
|
|
285
|
+
fallback_count += 1
|
|
286
|
+
logger.debug(
|
|
287
|
+
f"Using {secondary_name} handler as fallback (no {primary_name} match)",
|
|
288
|
+
extra={
|
|
289
|
+
"handler_id": descriptor.handler_id,
|
|
290
|
+
"handler_name": descriptor.name,
|
|
291
|
+
"source": secondary_name,
|
|
292
|
+
},
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# NOTE: Validation errors from bootstrap and contract sources are intentionally
|
|
296
|
+
# combined WITHOUT deduplication. During migration, the same error appearing from
|
|
297
|
+
# BOTH sources helps distinguish handler-level issues (error in both) from
|
|
298
|
+
# source-specific configuration problems (error in only one). This preserves
|
|
299
|
+
# diagnostic signal that would be lost if we deduplicated.
|
|
300
|
+
all_errors: list[ModelHandlerValidationError] = list(
|
|
301
|
+
bootstrap_result.validation_errors
|
|
302
|
+
) + list(contract_result.validation_errors)
|
|
303
|
+
|
|
304
|
+
# Log structured counts for observability
|
|
305
|
+
logger.info(
|
|
306
|
+
"Handler resolution completed (HYBRID mode)",
|
|
307
|
+
extra={
|
|
308
|
+
"mode": self._mode.value,
|
|
309
|
+
"allow_bootstrap_override": self._allow_bootstrap_override,
|
|
310
|
+
"precedence": primary_name,
|
|
311
|
+
"contract_handler_count": len(contract_result.descriptors),
|
|
312
|
+
"bootstrap_handler_count": len(bootstrap_result.descriptors),
|
|
313
|
+
"fallback_handler_count": fallback_count,
|
|
314
|
+
"override_count": override_count,
|
|
315
|
+
"resolved_handler_count": len(handlers_by_id),
|
|
316
|
+
"validation_error_count": len(all_errors),
|
|
317
|
+
},
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
return ModelContractDiscoveryResult(
|
|
321
|
+
descriptors=list(handlers_by_id.values()),
|
|
322
|
+
validation_errors=all_errors,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
__all__ = ["HandlerSourceResolver"]
|
|
@@ -49,7 +49,7 @@ from omnibase_infra.runtime.models import (
|
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
if TYPE_CHECKING:
|
|
52
|
-
from
|
|
52
|
+
from omnibase_infra.protocols import ProtocolContainerAware
|
|
53
53
|
|
|
54
54
|
logger = logging.getLogger(__name__)
|
|
55
55
|
|
|
@@ -172,7 +172,7 @@ class ProtocolLifecycleExecutor:
|
|
|
172
172
|
return self._health_check_timeout_seconds
|
|
173
173
|
|
|
174
174
|
@staticmethod
|
|
175
|
-
def get_shutdown_priority(handler:
|
|
175
|
+
def get_shutdown_priority(handler: ProtocolContainerAware) -> int:
|
|
176
176
|
"""Get shutdown priority for a handler.
|
|
177
177
|
|
|
178
178
|
Returns the shutdown priority for the given handler. Handlers with higher
|
|
@@ -225,7 +225,7 @@ class ProtocolLifecycleExecutor:
|
|
|
225
225
|
async def shutdown_handler(
|
|
226
226
|
self,
|
|
227
227
|
handler_type: str,
|
|
228
|
-
handler:
|
|
228
|
+
handler: ProtocolContainerAware,
|
|
229
229
|
) -> ModelLifecycleResult:
|
|
230
230
|
"""Shutdown a single handler with error handling.
|
|
231
231
|
|
|
@@ -267,7 +267,7 @@ class ProtocolLifecycleExecutor:
|
|
|
267
267
|
async def check_handler_health(
|
|
268
268
|
self,
|
|
269
269
|
handler_type: str,
|
|
270
|
-
handler:
|
|
270
|
+
handler: ProtocolContainerAware,
|
|
271
271
|
timeout_seconds: float = -1.0,
|
|
272
272
|
) -> ModelHealthCheckResult:
|
|
273
273
|
"""Check health of a single handler with timeout.
|
|
@@ -329,7 +329,7 @@ class ProtocolLifecycleExecutor:
|
|
|
329
329
|
|
|
330
330
|
async def shutdown_handlers_by_priority(
|
|
331
331
|
self,
|
|
332
|
-
handlers: dict[str,
|
|
332
|
+
handlers: dict[str, ProtocolContainerAware],
|
|
333
333
|
) -> ModelBatchLifecycleResult:
|
|
334
334
|
"""Shutdown all handlers grouped by priority (higher first, parallel within group).
|
|
335
335
|
|
|
@@ -359,7 +359,7 @@ class ProtocolLifecycleExecutor:
|
|
|
359
359
|
return ModelBatchLifecycleResult.empty()
|
|
360
360
|
|
|
361
361
|
# Group handlers by priority
|
|
362
|
-
priority_groups: dict[int, list[tuple[str,
|
|
362
|
+
priority_groups: dict[int, list[tuple[str, ProtocolContainerAware]]] = {}
|
|
363
363
|
for handler_type, handler in handlers.items():
|
|
364
364
|
priority = self.get_shutdown_priority(handler)
|
|
365
365
|
if priority not in priority_groups:
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"""Protocol Binding Registry - SINGLE SOURCE OF TRUTH for handler registration.
|
|
4
4
|
|
|
5
5
|
This module provides the RegistryProtocolBinding class which implements the
|
|
6
|
-
|
|
6
|
+
ProtocolContainerAwareRegistry protocol from omnibase_spi. It serves as the
|
|
7
7
|
centralized location for registering and resolving protocol handlers
|
|
8
8
|
in the omnibase_infra layer.
|
|
9
9
|
|
|
10
10
|
The registry is responsible for:
|
|
11
|
-
- Registering
|
|
12
|
-
- Resolving handler classes for protocol types
|
|
11
|
+
- Registering infrastructure handlers by protocol type identifier
|
|
12
|
+
- Resolving handler classes for protocol types (requires ProtocolContainerAware)
|
|
13
13
|
- Thread-safe registration operations
|
|
14
14
|
- Listing all registered protocol types
|
|
15
15
|
|
|
@@ -70,7 +70,7 @@ from typing import TYPE_CHECKING, Any, cast
|
|
|
70
70
|
from omnibase_infra.errors import ModelInfraErrorContext, RuntimeHostError
|
|
71
71
|
|
|
72
72
|
if TYPE_CHECKING:
|
|
73
|
-
from
|
|
73
|
+
from omnibase_infra.protocols import ProtocolContainerAware
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
# =============================================================================
|
|
@@ -131,11 +131,11 @@ class RegistryError(RuntimeHostError):
|
|
|
131
131
|
class RegistryProtocolBinding:
|
|
132
132
|
"""SINGLE SOURCE OF TRUTH for handler registration in omnibase_infra.
|
|
133
133
|
|
|
134
|
-
Thread-safe registry for protocol handlers. Implements
|
|
134
|
+
Thread-safe registry for protocol handlers. Implements ProtocolContainerAwareRegistry
|
|
135
135
|
protocol from omnibase_spi.
|
|
136
136
|
|
|
137
137
|
The registry maintains a mapping from protocol type identifiers (strings like
|
|
138
|
-
"http", "db", "kafka") to handler classes that implement the
|
|
138
|
+
"http", "db", "kafka") to handler classes that implement the ProtocolContainerAware
|
|
139
139
|
protocol.
|
|
140
140
|
|
|
141
141
|
TODO(OMN-40): Migrate handler signature from tuple[str, str] to structured model.
|
|
@@ -163,13 +163,13 @@ class RegistryProtocolBinding:
|
|
|
163
163
|
|
|
164
164
|
def __init__(self) -> None:
|
|
165
165
|
"""Initialize an empty handler registry with thread lock."""
|
|
166
|
-
self._registry: dict[str, type[
|
|
166
|
+
self._registry: dict[str, type[ProtocolContainerAware]] = {}
|
|
167
167
|
self._lock: threading.Lock = threading.Lock()
|
|
168
168
|
|
|
169
169
|
def register(
|
|
170
170
|
self,
|
|
171
171
|
protocol_type: str,
|
|
172
|
-
handler_cls: type[
|
|
172
|
+
handler_cls: type[ProtocolContainerAware],
|
|
173
173
|
) -> None:
|
|
174
174
|
"""Register a protocol handler.
|
|
175
175
|
|
|
@@ -219,10 +219,10 @@ class RegistryProtocolBinding:
|
|
|
219
219
|
Args:
|
|
220
220
|
protocol_type: Protocol type identifier (e.g., 'http', 'db', 'kafka').
|
|
221
221
|
Should be one of the HANDLER_TYPE_* constants.
|
|
222
|
-
handler_cls: Handler class implementing the
|
|
222
|
+
handler_cls: Handler class implementing the ProtocolContainerAware protocol.
|
|
223
223
|
|
|
224
224
|
Raises:
|
|
225
|
-
RegistryError: If handler_cls does not implement the
|
|
225
|
+
RegistryError: If handler_cls does not implement the ProtocolContainerAware protocol
|
|
226
226
|
(missing or non-callable execute()/handle() method).
|
|
227
227
|
|
|
228
228
|
Example:
|
|
@@ -230,7 +230,7 @@ class RegistryProtocolBinding:
|
|
|
230
230
|
>>> registry.register(HANDLER_TYPE_HTTP, HttpHandler)
|
|
231
231
|
>>> registry.register(HANDLER_TYPE_DATABASE, PostgresHandler)
|
|
232
232
|
"""
|
|
233
|
-
# Runtime type validation: Ensure handler_cls implements
|
|
233
|
+
# Runtime type validation: Ensure handler_cls implements ProtocolContainerAware protocol
|
|
234
234
|
# Check if execute() or handle() method exists and is callable
|
|
235
235
|
# Following RegistryEventBusBinding pattern of supporting alternative methods
|
|
236
236
|
has_execute = hasattr(handler_cls, "execute")
|
|
@@ -240,7 +240,7 @@ class RegistryProtocolBinding:
|
|
|
240
240
|
raise RegistryError(
|
|
241
241
|
f"Handler class {handler_cls.__name__!r} for protocol type "
|
|
242
242
|
f"{protocol_type!r} is missing 'execute()' or 'handle()' method "
|
|
243
|
-
f"from
|
|
243
|
+
f"from ProtocolContainerAware protocol",
|
|
244
244
|
protocol_type=protocol_type,
|
|
245
245
|
context=ModelInfraErrorContext.with_correlation(
|
|
246
246
|
operation="register",
|
|
@@ -279,7 +279,7 @@ class RegistryProtocolBinding:
|
|
|
279
279
|
def get(
|
|
280
280
|
self,
|
|
281
281
|
protocol_type: str,
|
|
282
|
-
) -> type[
|
|
282
|
+
) -> type[ProtocolContainerAware]:
|
|
283
283
|
"""Get handler class for protocol type.
|
|
284
284
|
|
|
285
285
|
Resolves the handler class registered for the given protocol type.
|