Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 127 additions & 26 deletions src/omnibase_core/container/service_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,37 @@

import time
from datetime import datetime
from typing import Any, Literal, TypeVar, cast
from typing import Literal, TypeVar, cast
from uuid import UUID, uuid4

from omnibase_core.enums.enum_core_error_code import EnumCoreErrorCode
from omnibase_core.enums.enum_log_level import EnumLogLevel
from omnibase_core.logging.structured import emit_log_event_sync as emit_log_event
from omnibase_core.models.container.model_injection_context import ModelInjectionContext
from omnibase_core.models.container.model_registry_config import (
ModelServiceRegistryConfig,
)
from omnibase_core.models.container.model_registry_status import (
ModelServiceRegistryStatus,
)
from omnibase_core.models.container.model_service_dependency_graph import (
ModelServiceDependencyGraph,
)
from omnibase_core.models.container.model_service_health_validation_result import (
ModelServiceHealthValidationResult,
)
from omnibase_core.models.container.model_service_instance import ModelServiceInstance
from omnibase_core.models.container.model_service_metadata import ModelServiceMetadata
from omnibase_core.models.container.model_service_registration import (
ModelServiceRegistration,
)
from omnibase_core.models.errors.model_onex_error import ModelOnexError
from omnibase_core.protocols import LiteralInjectionScope, LiteralServiceLifecycle
from omnibase_core.protocols import (
LiteralInjectionScope,
LiteralServiceLifecycle,
ProtocolServiceFactory,
ProtocolServiceValidator,
)
from omnibase_core.types.type_serializable_value import SerializedDict
from omnibase_core.types.typed_dict_resolution_context import TypedDictResolutionContext

Expand Down Expand Up @@ -104,12 +116,12 @@ def config(self) -> ModelServiceRegistryConfig:
return self._config

@property
def validator(self) -> Any | None:
def validator(self) -> ProtocolServiceValidator | None:
"""Get service validator (not implemented in v1.0)."""
return None

@property
def factory(self) -> Any | None:
def factory(self) -> ProtocolServiceFactory | None:
"""Get service factory (not implemented in v1.0)."""
return None

Expand Down Expand Up @@ -313,7 +325,7 @@ async def register_instance(
async def register_factory(
self,
interface: type[TInterface],
factory: Any,
factory: ProtocolServiceFactory,
lifecycle: LiteralServiceLifecycle = "transient",
scope: LiteralInjectionScope = "global",
) -> UUID:
Expand All @@ -322,7 +334,7 @@ async def register_factory(

Args:
interface: Interface protocol type
factory: Service factory
factory: Service factory implementing ProtocolServiceFactory
lifecycle: Lifecycle pattern
scope: Injection scope

Expand Down Expand Up @@ -549,7 +561,7 @@ async def resolve_all_services(
instance = await self._resolve_by_lifecycle(
registration_id, registration, scope or registration.scope, None
)
instances.append(instance)
instances.append(cast(TInterface, instance))

return instances

Expand Down Expand Up @@ -703,17 +715,39 @@ async def detect_circular_dependencies(
# Not implemented in v1.0 - no dependency tracking yet
return []

async def get_dependency_graph(self, service_id: UUID) -> Any | None:
async def get_dependency_graph(
self, service_id: UUID
) -> ModelServiceDependencyGraph | None:
"""
Get dependency graph (not implemented in v1.0).
Get dependency graph for a service.

Returns the dependency graph for the specified service, including
its dependencies, dependents, and resolution order.

Note: Dependency tracking is not fully implemented in v1.0.
This method returns a minimal graph with only basic information.

Args:
service_id: Service ID
service_id: Service registration ID

Returns:
None (not implemented in v1.0)
ModelServiceDependencyGraph with dependency information,
or None if service not found
"""
return None
# Check if service exists
if service_id not in self._registrations:
return None

# In v1.0, we don't track dependencies, so return a minimal graph
return ModelServiceDependencyGraph(
service_id=service_id,
dependencies=[],
dependents=[],
depth_level=0,
circular_references=[],
resolution_order=[service_id],
metadata={"note": "Dependency tracking not implemented in v1.0"},
)

async def get_registry_status(self) -> ModelServiceRegistryStatus:
"""
Expand Down Expand Up @@ -775,21 +809,78 @@ async def get_registry_status(self) -> ModelServiceRegistryStatus:
last_updated=datetime.now(),
)

async def validate_service_health(self, registration_id: UUID) -> Any:
async def validate_service_health(
self, registration_id: UUID
) -> ModelServiceHealthValidationResult:
"""
Validate service health (not fully implemented in v1.0).
Validate service health.

Performs health validation on the specified service registration,
checking instance availability and basic health metrics.

Args:
registration_id: Registration ID
registration_id: Registration ID to validate

Returns:
Validation result
ModelServiceHealthValidationResult with health information

Raises:
ModelOnexError: If registration not found
"""
msg = "Service health validation not yet fully implemented (planned for v2.0)"
raise ModelOnexError(
message=msg,
error_code=EnumCoreErrorCode.METHOD_NOT_IMPLEMENTED,
start_time = time.perf_counter()

# Check if registration exists
if registration_id not in self._registrations:
return ModelServiceHealthValidationResult.unhealthy(
registration_id=registration_id,
error_message=f"Registration not found: {registration_id}",
diagnostics={"available_registrations": len(self._registrations)},
)

registration = self._registrations[registration_id]
instances = self._instances.get(registration_id, [])
active_instances = [inst for inst in instances if inst.is_active()]

end_time = time.perf_counter()
response_time_ms = (end_time - start_time) * 1000

# Check for issues
warnings: list[str] = []

if not active_instances and registration.lifecycle == "singleton":
# Singleton with no instances might indicate a problem
warnings.append("Singleton service has no active instances")

# Check last access time
last_access: datetime | None = None
if active_instances:
last_access = max(inst.last_accessed for inst in active_instances)

# Determine health status
if registration.health_status == "unhealthy":
return ModelServiceHealthValidationResult.unhealthy(
registration_id=registration_id,
error_message="Service marked as unhealthy",
diagnostics={
"registration_status": registration.registration_status,
"lifecycle": registration.lifecycle,
},
)

if warnings:
return ModelServiceHealthValidationResult.degraded(
registration_id=registration_id,
warnings=warnings,
instance_count=len(active_instances),
)

result = ModelServiceHealthValidationResult.healthy(
registration_id=registration_id,
instance_count=len(active_instances),
response_time_ms=response_time_ms,
)
result.last_access_time = last_access
return result

async def update_service_configuration(
self, registration_id: UUID, configuration: SerializedDict
Expand Down Expand Up @@ -854,24 +945,34 @@ async def dispose_injection_scope(self, scope_id: UUID) -> int:
error_code=EnumCoreErrorCode.METHOD_NOT_IMPLEMENTED,
)

async def get_injection_context(self, context_id: UUID) -> Any | None:
async def get_injection_context(
self, context_id: UUID
) -> ModelInjectionContext | None:
"""
Get injection context (not implemented in v1.0).
Get injection context by ID.

Returns the injection context for the specified context ID,
including resolution status and dependency path information.

Note: Context tracking is not fully implemented in v1.0.
This method currently returns None as contexts are not persisted.

Args:
context_id: Context ID
context_id: Context ID to look up

Returns:
None (not implemented in v1.0)
ModelInjectionContext if found, None otherwise
"""
# In v1.0, we don't persist injection contexts
# Full context tracking is planned for v2.0
return None

# Private helper methods

async def _store_instance(
self,
registration_id: UUID,
instance: Any,
instance: object,
lifecycle: LiteralServiceLifecycle,
scope: LiteralInjectionScope,
) -> ModelServiceInstance:
Expand Down Expand Up @@ -903,7 +1004,7 @@ async def _resolve_by_lifecycle(
registration: ModelServiceRegistration,
scope: LiteralInjectionScope,
context: TypedDictResolutionContext | None,
) -> Any:
) -> object:
"""Resolve service based on lifecycle pattern."""
lifecycle = registration.lifecycle

Expand Down
14 changes: 12 additions & 2 deletions src/omnibase_core/models/container/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from omnibase_core.models.container.model_base_model_onex_container import (
_BaseModelONEXContainer,
)
from omnibase_core.models.container.model_injection_context import ModelInjectionContext
from omnibase_core.models.container.model_onex_container import (
ModelONEXContainer,
create_model_onex_container,
Expand All @@ -18,6 +19,12 @@
from omnibase_core.models.container.model_registry_status import (
ModelServiceRegistryStatus,
)
from omnibase_core.models.container.model_service_dependency_graph import (
ModelServiceDependencyGraph,
)
from omnibase_core.models.container.model_service_health_validation_result import (
ModelServiceHealthValidationResult,
)
from omnibase_core.models.container.model_service_instance import ModelServiceInstance
from omnibase_core.models.container.model_service_metadata import ModelServiceMetadata
from omnibase_core.models.container.model_service_registration import (
Expand All @@ -26,12 +33,15 @@

__all__ = [
"_BaseModelONEXContainer",
"ModelInjectionContext",
"ModelONEXContainer",
"ModelServiceRegistryConfig",
"ModelServiceRegistryStatus",
"ModelServiceDependencyGraph",
"ModelServiceHealthValidationResult",
"ModelServiceInstance",
"ModelServiceMetadata",
"ModelServiceRegistration",
"ModelServiceRegistryConfig",
"ModelServiceRegistryStatus",
"create_model_onex_container",
"get_model_onex_container",
"get_model_onex_container_sync",
Expand Down
Loading
Loading