omnibase_infra 0.2.8__py3-none-any.whl → 0.3.0__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/enums/__init__.py +4 -0
- omnibase_infra/enums/enum_declarative_node_violation.py +102 -0
- omnibase_infra/errors/__init__.py +18 -0
- omnibase_infra/errors/repository/__init__.py +78 -0
- omnibase_infra/errors/repository/errors_repository.py +424 -0
- omnibase_infra/event_bus/adapters/__init__.py +31 -0
- omnibase_infra/event_bus/adapters/adapter_protocol_event_publisher_kafka.py +517 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +113 -1
- omnibase_infra/models/__init__.py +9 -0
- omnibase_infra/models/event_bus/__init__.py +22 -0
- omnibase_infra/models/event_bus/model_consumer_retry_config.py +367 -0
- omnibase_infra/models/event_bus/model_dlq_config.py +177 -0
- omnibase_infra/models/event_bus/model_idempotency_config.py +131 -0
- omnibase_infra/models/event_bus/model_offset_policy_config.py +107 -0
- omnibase_infra/models/resilience/model_circuit_breaker_config.py +15 -0
- omnibase_infra/models/validation/__init__.py +8 -0
- omnibase_infra/models/validation/model_declarative_node_validation_result.py +139 -0
- omnibase_infra/models/validation/model_declarative_node_violation.py +169 -0
- omnibase_infra/nodes/architecture_validator/__init__.py +28 -7
- omnibase_infra/nodes/architecture_validator/constants.py +36 -0
- omnibase_infra/nodes/architecture_validator/handlers/__init__.py +28 -0
- omnibase_infra/nodes/architecture_validator/handlers/contract.yaml +120 -0
- omnibase_infra/nodes/architecture_validator/handlers/handler_architecture_validation.py +359 -0
- omnibase_infra/nodes/architecture_validator/node.py +1 -0
- omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +48 -336
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +12 -2
- omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +16 -2
- omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +14 -4
- omnibase_infra/nodes/node_ledger_projection_compute/handlers/__init__.py +18 -0
- omnibase_infra/nodes/node_ledger_projection_compute/handlers/contract.yaml +53 -0
- omnibase_infra/nodes/node_ledger_projection_compute/handlers/handler_ledger_projection.py +354 -0
- omnibase_infra/nodes/node_ledger_projection_compute/node.py +20 -256
- omnibase_infra/nodes/node_registry_effect/node.py +20 -73
- omnibase_infra/protocols/protocol_dispatch_engine.py +90 -0
- omnibase_infra/runtime/__init__.py +11 -0
- omnibase_infra/runtime/baseline_subscriptions.py +150 -0
- omnibase_infra/runtime/db/__init__.py +73 -0
- omnibase_infra/runtime/db/models/__init__.py +41 -0
- omnibase_infra/runtime/db/models/model_repository_runtime_config.py +211 -0
- omnibase_infra/runtime/db/postgres_repository_runtime.py +545 -0
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +455 -24
- omnibase_infra/runtime/kafka_contract_source.py +13 -5
- omnibase_infra/runtime/service_message_dispatch_engine.py +112 -0
- omnibase_infra/runtime/service_runtime_host_process.py +6 -11
- omnibase_infra/services/__init__.py +36 -0
- omnibase_infra/services/contract_publisher/__init__.py +95 -0
- omnibase_infra/services/contract_publisher/config.py +199 -0
- omnibase_infra/services/contract_publisher/errors.py +243 -0
- omnibase_infra/services/contract_publisher/models/__init__.py +28 -0
- omnibase_infra/services/contract_publisher/models/model_contract_error.py +67 -0
- omnibase_infra/services/contract_publisher/models/model_infra_error.py +62 -0
- omnibase_infra/services/contract_publisher/models/model_publish_result.py +112 -0
- omnibase_infra/services/contract_publisher/models/model_publish_stats.py +79 -0
- omnibase_infra/services/contract_publisher/service.py +617 -0
- omnibase_infra/services/contract_publisher/sources/__init__.py +52 -0
- omnibase_infra/services/contract_publisher/sources/model_discovered.py +155 -0
- omnibase_infra/services/contract_publisher/sources/protocol.py +101 -0
- omnibase_infra/services/contract_publisher/sources/source_composite.py +309 -0
- omnibase_infra/services/contract_publisher/sources/source_filesystem.py +174 -0
- omnibase_infra/services/contract_publisher/sources/source_package.py +221 -0
- omnibase_infra/services/observability/__init__.py +40 -0
- omnibase_infra/services/observability/agent_actions/__init__.py +64 -0
- omnibase_infra/services/observability/agent_actions/config.py +209 -0
- omnibase_infra/services/observability/agent_actions/consumer.py +1320 -0
- omnibase_infra/services/observability/agent_actions/models/__init__.py +87 -0
- omnibase_infra/services/observability/agent_actions/models/model_agent_action.py +142 -0
- omnibase_infra/services/observability/agent_actions/models/model_detection_failure.py +125 -0
- omnibase_infra/services/observability/agent_actions/models/model_envelope.py +85 -0
- omnibase_infra/services/observability/agent_actions/models/model_execution_log.py +159 -0
- omnibase_infra/services/observability/agent_actions/models/model_performance_metric.py +130 -0
- omnibase_infra/services/observability/agent_actions/models/model_routing_decision.py +138 -0
- omnibase_infra/services/observability/agent_actions/models/model_transformation_event.py +124 -0
- omnibase_infra/services/observability/agent_actions/tests/__init__.py +20 -0
- omnibase_infra/services/observability/agent_actions/tests/test_consumer.py +1154 -0
- omnibase_infra/services/observability/agent_actions/tests/test_models.py +645 -0
- omnibase_infra/services/observability/agent_actions/tests/test_writer.py +709 -0
- omnibase_infra/services/observability/agent_actions/writer_postgres.py +926 -0
- omnibase_infra/validation/__init__.py +12 -0
- omnibase_infra/validation/contracts/declarative_node.validation.yaml +143 -0
- omnibase_infra/validation/infra_validators.py +4 -1
- omnibase_infra/validation/validation_exemptions.yaml +111 -0
- omnibase_infra/validation/validator_declarative_node.py +850 -0
- {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/METADATA +2 -2
- {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/RECORD +88 -30
- {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/licenses/LICENSE +0 -0
omnibase_infra/__init__.py
CHANGED
omnibase_infra/enums/__init__.py
CHANGED
|
@@ -57,6 +57,9 @@ from omnibase_infra.enums.enum_circuit_state import EnumCircuitState
|
|
|
57
57
|
from omnibase_infra.enums.enum_confirmation_event_type import EnumConfirmationEventType
|
|
58
58
|
from omnibase_infra.enums.enum_consumer_group_purpose import EnumConsumerGroupPurpose
|
|
59
59
|
from omnibase_infra.enums.enum_contract_type import EnumContractType
|
|
60
|
+
from omnibase_infra.enums.enum_declarative_node_violation import (
|
|
61
|
+
EnumDeclarativeNodeViolation,
|
|
62
|
+
)
|
|
60
63
|
from omnibase_infra.enums.enum_dedupe_strategy import EnumDedupeStrategy
|
|
61
64
|
from omnibase_infra.enums.enum_dispatch_status import EnumDispatchStatus
|
|
62
65
|
from omnibase_infra.enums.enum_environment import EnumEnvironment
|
|
@@ -101,6 +104,7 @@ __all__: list[str] = [
|
|
|
101
104
|
"EnumConfirmationEventType",
|
|
102
105
|
"EnumConsumerGroupPurpose",
|
|
103
106
|
"EnumContractType",
|
|
107
|
+
"EnumDeclarativeNodeViolation",
|
|
104
108
|
"EnumDedupeStrategy",
|
|
105
109
|
"EnumDispatchStatus",
|
|
106
110
|
"EnumEnvironment",
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Enum for declarative node violation categories.
|
|
4
|
+
|
|
5
|
+
Defines the specific violation types detected by the declarative node validator.
|
|
6
|
+
Following the ONEX declarative pattern policy:
|
|
7
|
+
- Node classes MUST only extend base classes without custom logic
|
|
8
|
+
- Only __init__ with super().__init__(container) is allowed
|
|
9
|
+
- No custom methods, properties, or instance variables
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from enum import Enum
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EnumDeclarativeNodeViolation(str, Enum):
|
|
16
|
+
"""Violation types for declarative node pattern enforcement.
|
|
17
|
+
|
|
18
|
+
These violation types correspond to the ONEX declarative node policy:
|
|
19
|
+
Nodes must be contract-driven with no custom Python logic.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
CUSTOM_METHOD: Node class contains custom method (not __init__).
|
|
23
|
+
CUSTOM_PROPERTY: Node class contains property definition.
|
|
24
|
+
INIT_CUSTOM_LOGIC: __init__ contains logic beyond super().__init__().
|
|
25
|
+
INSTANCE_VARIABLE: __init__ creates custom instance variables.
|
|
26
|
+
CLASS_VARIABLE: Node class defines class-level variables.
|
|
27
|
+
SYNTAX_ERROR: File has Python syntax error, cannot validate.
|
|
28
|
+
NO_NODE_CLASS: File named node.py but contains no node class.
|
|
29
|
+
|
|
30
|
+
Policy Summary:
|
|
31
|
+
- ALLOWED: ``class MyNode(NodeEffect): pass``
|
|
32
|
+
- ALLOWED: ``def __init__(self, container): super().__init__(container)``
|
|
33
|
+
- BLOCKED: ``def compute(self, data): ...``
|
|
34
|
+
- BLOCKED: ``@property def my_prop(self): ...``
|
|
35
|
+
- BLOCKED: ``self._custom_var = value`` in __init__
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
CUSTOM_METHOD = "custom_method"
|
|
39
|
+
CUSTOM_PROPERTY = "custom_property"
|
|
40
|
+
INIT_CUSTOM_LOGIC = "init_custom_logic"
|
|
41
|
+
INSTANCE_VARIABLE = "instance_variable"
|
|
42
|
+
CLASS_VARIABLE = "class_variable"
|
|
43
|
+
SYNTAX_ERROR = "syntax_error"
|
|
44
|
+
NO_NODE_CLASS = "no_node_class"
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def is_exemptable(self) -> bool:
|
|
48
|
+
"""Check if this violation type can be exempted.
|
|
49
|
+
|
|
50
|
+
Some violations like SYNTAX_ERROR cannot be exempted because
|
|
51
|
+
they indicate fundamental issues with the source file.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
True if the violation type can be exempted via decorator or comment.
|
|
55
|
+
"""
|
|
56
|
+
return self not in {
|
|
57
|
+
EnumDeclarativeNodeViolation.SYNTAX_ERROR,
|
|
58
|
+
EnumDeclarativeNodeViolation.NO_NODE_CLASS,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def suggestion(self) -> str:
|
|
63
|
+
"""Get the suggested fix for this violation type.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Human-readable suggestion for fixing the violation.
|
|
67
|
+
"""
|
|
68
|
+
suggestions = {
|
|
69
|
+
EnumDeclarativeNodeViolation.CUSTOM_METHOD: (
|
|
70
|
+
"Move business logic to a Handler class. Node classes must be "
|
|
71
|
+
"declarative - all behavior should be defined in contract.yaml "
|
|
72
|
+
"and implemented by handlers."
|
|
73
|
+
),
|
|
74
|
+
EnumDeclarativeNodeViolation.CUSTOM_PROPERTY: (
|
|
75
|
+
"Remove property from node class. Node classes should not have "
|
|
76
|
+
"custom properties - use container dependency injection instead."
|
|
77
|
+
),
|
|
78
|
+
EnumDeclarativeNodeViolation.INIT_CUSTOM_LOGIC: (
|
|
79
|
+
"Remove custom logic from __init__. The __init__ method should "
|
|
80
|
+
"only call super().__init__(container). All initialization should "
|
|
81
|
+
"be handled by the base class and contract.yaml."
|
|
82
|
+
),
|
|
83
|
+
EnumDeclarativeNodeViolation.INSTANCE_VARIABLE: (
|
|
84
|
+
"Remove instance variable assignment from __init__. Node classes "
|
|
85
|
+
"should not store state - use container injection and handlers."
|
|
86
|
+
),
|
|
87
|
+
EnumDeclarativeNodeViolation.CLASS_VARIABLE: (
|
|
88
|
+
"Remove class variable from node class. Configuration should be "
|
|
89
|
+
"in contract.yaml, not Python code."
|
|
90
|
+
),
|
|
91
|
+
EnumDeclarativeNodeViolation.SYNTAX_ERROR: (
|
|
92
|
+
"Fix the Python syntax error before validation can proceed."
|
|
93
|
+
),
|
|
94
|
+
EnumDeclarativeNodeViolation.NO_NODE_CLASS: (
|
|
95
|
+
"File is named node.py but does not contain a Node class. "
|
|
96
|
+
"Either add a Node class or rename the file."
|
|
97
|
+
),
|
|
98
|
+
}
|
|
99
|
+
return suggestions.get(self, "Make the node class declarative.")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
__all__ = ["EnumDeclarativeNodeViolation"]
|
|
@@ -23,6 +23,11 @@ Exports:
|
|
|
23
23
|
ChainPropagationError: Correlation/causation chain validation errors
|
|
24
24
|
ArchitectureViolationError: Architecture validation errors (blocks startup)
|
|
25
25
|
BindingResolutionError: Binding resolution errors (declarative operation bindings)
|
|
26
|
+
RepositoryError: Base error for repository operations
|
|
27
|
+
RepositoryContractError: Contract-level errors (bad op_name, missing params)
|
|
28
|
+
RepositoryValidationError: Validation errors (type mismatch, constraints)
|
|
29
|
+
RepositoryExecutionError: Execution errors (asyncpg, connection issues)
|
|
30
|
+
RepositoryTimeoutError: Query timeout exceeded
|
|
26
31
|
|
|
27
32
|
Correlation ID Assignment:
|
|
28
33
|
All infrastructure errors support correlation_id for distributed tracing.
|
|
@@ -117,6 +122,13 @@ from omnibase_infra.errors.error_infra import (
|
|
|
117
122
|
from omnibase_infra.errors.error_message_type_registry import MessageTypeRegistryError
|
|
118
123
|
from omnibase_infra.errors.error_policy_registry import PolicyRegistryError
|
|
119
124
|
from omnibase_infra.errors.error_vault import InfraVaultError
|
|
125
|
+
from omnibase_infra.errors.repository import (
|
|
126
|
+
RepositoryContractError,
|
|
127
|
+
RepositoryError,
|
|
128
|
+
RepositoryExecutionError,
|
|
129
|
+
RepositoryTimeoutError,
|
|
130
|
+
RepositoryValidationError,
|
|
131
|
+
)
|
|
120
132
|
from omnibase_infra.models.errors.model_infra_error_context import (
|
|
121
133
|
ModelInfraErrorContext,
|
|
122
134
|
)
|
|
@@ -150,6 +162,12 @@ __all__: list[str] = [
|
|
|
150
162
|
"ModelTimeoutErrorContext",
|
|
151
163
|
"PolicyRegistryError",
|
|
152
164
|
"ProtocolConfigurationError",
|
|
165
|
+
# Repository errors
|
|
166
|
+
"RepositoryContractError",
|
|
167
|
+
"RepositoryError",
|
|
168
|
+
"RepositoryExecutionError",
|
|
169
|
+
"RepositoryTimeoutError",
|
|
170
|
+
"RepositoryValidationError",
|
|
153
171
|
# Error classes
|
|
154
172
|
"RuntimeHostError",
|
|
155
173
|
"SecretResolutionError",
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Repository Error Classes Module.
|
|
4
|
+
|
|
5
|
+
This module provides error classes specific to repository operations,
|
|
6
|
+
enabling typed exception handling for the PostgresRepositoryRuntime.
|
|
7
|
+
|
|
8
|
+
Error Hierarchy:
|
|
9
|
+
RuntimeHostError (from omnibase_infra.errors)
|
|
10
|
+
└── RepositoryError (base repository error)
|
|
11
|
+
├── RepositoryContractError (contract-level errors)
|
|
12
|
+
├── RepositoryValidationError (validation errors)
|
|
13
|
+
├── RepositoryExecutionError (execution errors)
|
|
14
|
+
└── RepositoryTimeoutError (query timeout errors)
|
|
15
|
+
|
|
16
|
+
Exports:
|
|
17
|
+
RepositoryError: Base error for all repository operations
|
|
18
|
+
RepositoryContractError: Bad op_name, missing params, forbidden op
|
|
19
|
+
RepositoryValidationError: Param type mismatch, constraint violation
|
|
20
|
+
RepositoryExecutionError: asyncpg errors, connection issues
|
|
21
|
+
RepositoryTimeoutError: Query timeout exceeded
|
|
22
|
+
|
|
23
|
+
Common Fields (all exceptions):
|
|
24
|
+
op_name: str | None - Operation name from repository contract
|
|
25
|
+
table: str | None - Target table for the operation
|
|
26
|
+
retriable: bool - Whether the operation can be retried
|
|
27
|
+
sql_fingerprint: str | None - SQL fingerprint for query tracking
|
|
28
|
+
|
|
29
|
+
Example Usage::
|
|
30
|
+
|
|
31
|
+
from omnibase_infra.errors.repository import (
|
|
32
|
+
RepositoryContractError,
|
|
33
|
+
RepositoryExecutionError,
|
|
34
|
+
RepositoryTimeoutError,
|
|
35
|
+
RepositoryValidationError,
|
|
36
|
+
)
|
|
37
|
+
from omnibase_infra.models.errors import ModelInfraErrorContext
|
|
38
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
39
|
+
|
|
40
|
+
# Contract error - unknown operation
|
|
41
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
42
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
43
|
+
operation="execute_operation",
|
|
44
|
+
)
|
|
45
|
+
raise RepositoryContractError(
|
|
46
|
+
"Unknown operation 'invalid_op'",
|
|
47
|
+
op_name="invalid_op",
|
|
48
|
+
table="users",
|
|
49
|
+
context=context,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Check retriability in error handling
|
|
53
|
+
try:
|
|
54
|
+
result = await runtime.execute("find_all", {})
|
|
55
|
+
except RepositoryError as e:
|
|
56
|
+
if e.retriable:
|
|
57
|
+
# Can retry with backoff
|
|
58
|
+
pass
|
|
59
|
+
else:
|
|
60
|
+
# Non-retriable, propagate
|
|
61
|
+
raise
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
from omnibase_infra.errors.repository.errors_repository import (
|
|
65
|
+
RepositoryContractError,
|
|
66
|
+
RepositoryError,
|
|
67
|
+
RepositoryExecutionError,
|
|
68
|
+
RepositoryTimeoutError,
|
|
69
|
+
RepositoryValidationError,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
"RepositoryContractError",
|
|
74
|
+
"RepositoryError",
|
|
75
|
+
"RepositoryExecutionError",
|
|
76
|
+
"RepositoryTimeoutError",
|
|
77
|
+
"RepositoryValidationError",
|
|
78
|
+
]
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Repository Error Classes for PostgresRepositoryRuntime.
|
|
4
|
+
|
|
5
|
+
This module defines error classes specific to repository operations,
|
|
6
|
+
providing granular error handling for contract-driven database access.
|
|
7
|
+
|
|
8
|
+
Error Hierarchy:
|
|
9
|
+
RuntimeHostError (from error_infra)
|
|
10
|
+
└── RepositoryError (base repository error)
|
|
11
|
+
├── RepositoryContractError (contract-level errors)
|
|
12
|
+
├── RepositoryValidationError (validation errors)
|
|
13
|
+
├── RepositoryExecutionError (execution errors)
|
|
14
|
+
└── RepositoryTimeoutError (query timeout errors)
|
|
15
|
+
|
|
16
|
+
All errors:
|
|
17
|
+
- Extend RuntimeHostError for infrastructure consistency
|
|
18
|
+
- Include repository-specific fields: op_name, table, retriable
|
|
19
|
+
- Support optional sql_fingerprint for query tracking
|
|
20
|
+
- Use EnumCoreErrorCode for error classification
|
|
21
|
+
- Support correlation IDs for distributed tracing
|
|
22
|
+
|
|
23
|
+
Retriability Guidelines:
|
|
24
|
+
- RepositoryContractError: NOT retriable (contract/configuration issue)
|
|
25
|
+
- RepositoryValidationError: NOT retriable (data validation issue)
|
|
26
|
+
- RepositoryExecutionError: Generally retriable (transient failures)
|
|
27
|
+
- RepositoryTimeoutError: Retriable (timeout may be transient)
|
|
28
|
+
|
|
29
|
+
Example::
|
|
30
|
+
|
|
31
|
+
from omnibase_infra.errors.repository import (
|
|
32
|
+
RepositoryContractError,
|
|
33
|
+
RepositoryExecutionError,
|
|
34
|
+
RepositoryTimeoutError,
|
|
35
|
+
RepositoryValidationError,
|
|
36
|
+
)
|
|
37
|
+
from omnibase_infra.models.errors import ModelInfraErrorContext
|
|
38
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
39
|
+
|
|
40
|
+
# Contract error - unknown operation
|
|
41
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
42
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
43
|
+
operation="execute_operation",
|
|
44
|
+
)
|
|
45
|
+
raise RepositoryContractError(
|
|
46
|
+
"Unknown operation 'invalid_op' not defined in contract",
|
|
47
|
+
op_name="invalid_op",
|
|
48
|
+
table="users",
|
|
49
|
+
context=context,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Execution error with SQL fingerprint
|
|
53
|
+
raise RepositoryExecutionError(
|
|
54
|
+
"Connection pool exhausted",
|
|
55
|
+
op_name="find_by_id",
|
|
56
|
+
table="users",
|
|
57
|
+
sql_fingerprint="SELECT * FROM users WHERE id = $1",
|
|
58
|
+
context=context,
|
|
59
|
+
) from e
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
from omnibase_core.enums import EnumCoreErrorCode
|
|
63
|
+
from omnibase_infra.errors.error_infra import RuntimeHostError
|
|
64
|
+
from omnibase_infra.models.errors.model_infra_error_context import (
|
|
65
|
+
ModelInfraErrorContext,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class RepositoryError(RuntimeHostError):
|
|
70
|
+
"""Base error class for all repository operations.
|
|
71
|
+
|
|
72
|
+
Provides common structured fields for repository-specific errors:
|
|
73
|
+
- op_name: The operation name from the repository contract
|
|
74
|
+
- table: The target table for the operation
|
|
75
|
+
- retriable: Whether the operation can be retried
|
|
76
|
+
- sql_fingerprint: Optional SQL fingerprint for query tracking
|
|
77
|
+
|
|
78
|
+
Subclasses set default retriability based on error category:
|
|
79
|
+
- Contract errors: NOT retriable
|
|
80
|
+
- Validation errors: NOT retriable
|
|
81
|
+
- Execution errors: Generally retriable
|
|
82
|
+
- Timeout errors: Retriable
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
86
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
87
|
+
... operation="execute_operation",
|
|
88
|
+
... )
|
|
89
|
+
>>> raise RepositoryError(
|
|
90
|
+
... "Repository operation failed",
|
|
91
|
+
... op_name="find_by_id",
|
|
92
|
+
... table="users",
|
|
93
|
+
... context=context,
|
|
94
|
+
... )
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
# Default retriability for base class (conservative: not retriable)
|
|
98
|
+
_default_retriable: bool = False
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
message: str,
|
|
103
|
+
*,
|
|
104
|
+
op_name: str | None = None,
|
|
105
|
+
table: str | None = None,
|
|
106
|
+
retriable: bool | None = None,
|
|
107
|
+
sql_fingerprint: str | None = None,
|
|
108
|
+
error_code: EnumCoreErrorCode | None = None,
|
|
109
|
+
context: ModelInfraErrorContext | None = None,
|
|
110
|
+
**extra_context: object,
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Initialize RepositoryError with repository-specific fields.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
message: Human-readable error message
|
|
116
|
+
op_name: Operation name from the repository contract
|
|
117
|
+
table: Target table for the operation
|
|
118
|
+
retriable: Whether the operation can be retried. If None, uses
|
|
119
|
+
class default (_default_retriable)
|
|
120
|
+
sql_fingerprint: SQL fingerprint for query tracking (sanitized)
|
|
121
|
+
error_code: Error code (defaults to DATABASE_OPERATION_ERROR)
|
|
122
|
+
context: Bundled infrastructure context
|
|
123
|
+
**extra_context: Additional context information
|
|
124
|
+
"""
|
|
125
|
+
# Add repository-specific fields to extra_context
|
|
126
|
+
if op_name is not None:
|
|
127
|
+
extra_context["op_name"] = op_name
|
|
128
|
+
if table is not None:
|
|
129
|
+
extra_context["table"] = table
|
|
130
|
+
if sql_fingerprint is not None:
|
|
131
|
+
extra_context["sql_fingerprint"] = sql_fingerprint
|
|
132
|
+
|
|
133
|
+
# Resolve retriability: explicit > class default
|
|
134
|
+
resolved_retriable = (
|
|
135
|
+
retriable if retriable is not None else self._default_retriable
|
|
136
|
+
)
|
|
137
|
+
extra_context["retriable"] = resolved_retriable
|
|
138
|
+
|
|
139
|
+
# Store as instance attributes for programmatic access
|
|
140
|
+
self.op_name = op_name
|
|
141
|
+
self.table = table
|
|
142
|
+
self.retriable = resolved_retriable
|
|
143
|
+
self.sql_fingerprint = sql_fingerprint
|
|
144
|
+
|
|
145
|
+
super().__init__(
|
|
146
|
+
message=message,
|
|
147
|
+
error_code=error_code or EnumCoreErrorCode.DATABASE_OPERATION_ERROR,
|
|
148
|
+
context=context,
|
|
149
|
+
**extra_context,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class RepositoryContractError(RepositoryError):
|
|
154
|
+
"""Raised for contract-level errors in repository operations.
|
|
155
|
+
|
|
156
|
+
Used when:
|
|
157
|
+
- Operation name (op_name) is not defined in the contract
|
|
158
|
+
- Required parameters are missing for the operation
|
|
159
|
+
- Operation is explicitly forbidden in the contract
|
|
160
|
+
- Contract schema validation fails
|
|
161
|
+
|
|
162
|
+
Contract errors are NOT retriable - they indicate a configuration
|
|
163
|
+
or programming error that requires code or contract changes to fix.
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
167
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
168
|
+
... operation="execute_operation",
|
|
169
|
+
... )
|
|
170
|
+
>>> raise RepositoryContractError(
|
|
171
|
+
... "Operation 'drop_table' is forbidden in contract",
|
|
172
|
+
... op_name="drop_table",
|
|
173
|
+
... table="users",
|
|
174
|
+
... context=context,
|
|
175
|
+
... )
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
_default_retriable: bool = False
|
|
179
|
+
|
|
180
|
+
def __init__(
|
|
181
|
+
self,
|
|
182
|
+
message: str,
|
|
183
|
+
*,
|
|
184
|
+
op_name: str | None = None,
|
|
185
|
+
table: str | None = None,
|
|
186
|
+
retriable: bool | None = None,
|
|
187
|
+
sql_fingerprint: str | None = None,
|
|
188
|
+
context: ModelInfraErrorContext | None = None,
|
|
189
|
+
**extra_context: object,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Initialize RepositoryContractError.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
message: Human-readable error message
|
|
195
|
+
op_name: Operation name that caused the contract error
|
|
196
|
+
table: Target table (if applicable)
|
|
197
|
+
retriable: Override default (False). Contract errors are
|
|
198
|
+
generally NOT retriable.
|
|
199
|
+
sql_fingerprint: SQL fingerprint (if applicable)
|
|
200
|
+
context: Bundled infrastructure context
|
|
201
|
+
**extra_context: Additional context information
|
|
202
|
+
"""
|
|
203
|
+
super().__init__(
|
|
204
|
+
message=message,
|
|
205
|
+
op_name=op_name,
|
|
206
|
+
table=table,
|
|
207
|
+
retriable=retriable,
|
|
208
|
+
sql_fingerprint=sql_fingerprint,
|
|
209
|
+
error_code=EnumCoreErrorCode.INVALID_CONFIGURATION,
|
|
210
|
+
context=context,
|
|
211
|
+
**extra_context,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class RepositoryValidationError(RepositoryError):
|
|
216
|
+
"""Raised for validation errors in repository operations.
|
|
217
|
+
|
|
218
|
+
Used when:
|
|
219
|
+
- Parameter type mismatches (e.g., string passed for int column)
|
|
220
|
+
- Constraint violations (e.g., null for non-nullable column)
|
|
221
|
+
- Value out of allowed range
|
|
222
|
+
- Invalid data format
|
|
223
|
+
|
|
224
|
+
Validation errors are NOT retriable - they indicate invalid input
|
|
225
|
+
data that must be corrected before retrying.
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
229
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
230
|
+
... operation="execute_operation",
|
|
231
|
+
... )
|
|
232
|
+
>>> raise RepositoryValidationError(
|
|
233
|
+
... "Parameter 'user_id' expected int, got str",
|
|
234
|
+
... op_name="find_by_id",
|
|
235
|
+
... table="users",
|
|
236
|
+
... context=context,
|
|
237
|
+
... param_name="user_id",
|
|
238
|
+
... expected_type="int",
|
|
239
|
+
... actual_type="str",
|
|
240
|
+
... )
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
_default_retriable: bool = False
|
|
244
|
+
|
|
245
|
+
def __init__(
|
|
246
|
+
self,
|
|
247
|
+
message: str,
|
|
248
|
+
*,
|
|
249
|
+
op_name: str | None = None,
|
|
250
|
+
table: str | None = None,
|
|
251
|
+
retriable: bool | None = None,
|
|
252
|
+
sql_fingerprint: str | None = None,
|
|
253
|
+
context: ModelInfraErrorContext | None = None,
|
|
254
|
+
**extra_context: object,
|
|
255
|
+
) -> None:
|
|
256
|
+
"""Initialize RepositoryValidationError.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
message: Human-readable error message
|
|
260
|
+
op_name: Operation name that triggered validation
|
|
261
|
+
table: Target table (if applicable)
|
|
262
|
+
retriable: Override default (False). Validation errors are
|
|
263
|
+
generally NOT retriable.
|
|
264
|
+
sql_fingerprint: SQL fingerprint (if applicable)
|
|
265
|
+
context: Bundled infrastructure context
|
|
266
|
+
**extra_context: Additional context (param_name, expected_type, etc.)
|
|
267
|
+
"""
|
|
268
|
+
super().__init__(
|
|
269
|
+
message=message,
|
|
270
|
+
op_name=op_name,
|
|
271
|
+
table=table,
|
|
272
|
+
retriable=retriable,
|
|
273
|
+
sql_fingerprint=sql_fingerprint,
|
|
274
|
+
error_code=EnumCoreErrorCode.VALIDATION_ERROR,
|
|
275
|
+
context=context,
|
|
276
|
+
**extra_context,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class RepositoryExecutionError(RepositoryError):
|
|
281
|
+
"""Raised for execution errors in repository operations.
|
|
282
|
+
|
|
283
|
+
Used when:
|
|
284
|
+
- asyncpg errors during query execution
|
|
285
|
+
- Connection pool exhaustion
|
|
286
|
+
- Database connection lost mid-operation
|
|
287
|
+
- Deadlock detected
|
|
288
|
+
- Serialization failures
|
|
289
|
+
|
|
290
|
+
Execution errors are generally retriable - they often indicate
|
|
291
|
+
transient failures that may succeed on retry with backoff.
|
|
292
|
+
|
|
293
|
+
Example:
|
|
294
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
295
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
296
|
+
... operation="execute_operation",
|
|
297
|
+
... )
|
|
298
|
+
>>> try:
|
|
299
|
+
... result = await pool.execute(sql, *params)
|
|
300
|
+
... except asyncpg.PostgresError as e:
|
|
301
|
+
... raise RepositoryExecutionError(
|
|
302
|
+
... f"Query execution failed: {e}",
|
|
303
|
+
... op_name="create_user",
|
|
304
|
+
... table="users",
|
|
305
|
+
... sql_fingerprint="INSERT INTO users (...) VALUES (...)",
|
|
306
|
+
... context=context,
|
|
307
|
+
... ) from e
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
_default_retriable: bool = True
|
|
311
|
+
|
|
312
|
+
def __init__(
|
|
313
|
+
self,
|
|
314
|
+
message: str,
|
|
315
|
+
*,
|
|
316
|
+
op_name: str | None = None,
|
|
317
|
+
table: str | None = None,
|
|
318
|
+
retriable: bool | None = None,
|
|
319
|
+
sql_fingerprint: str | None = None,
|
|
320
|
+
context: ModelInfraErrorContext | None = None,
|
|
321
|
+
**extra_context: object,
|
|
322
|
+
) -> None:
|
|
323
|
+
"""Initialize RepositoryExecutionError.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
message: Human-readable error message
|
|
327
|
+
op_name: Operation name that failed during execution
|
|
328
|
+
table: Target table (if applicable)
|
|
329
|
+
retriable: Override default (True). Set False for non-retriable
|
|
330
|
+
execution errors (e.g., constraint violations from DB).
|
|
331
|
+
sql_fingerprint: SQL fingerprint for query tracking
|
|
332
|
+
context: Bundled infrastructure context
|
|
333
|
+
**extra_context: Additional context (asyncpg error details, etc.)
|
|
334
|
+
"""
|
|
335
|
+
super().__init__(
|
|
336
|
+
message=message,
|
|
337
|
+
op_name=op_name,
|
|
338
|
+
table=table,
|
|
339
|
+
retriable=retriable,
|
|
340
|
+
sql_fingerprint=sql_fingerprint,
|
|
341
|
+
error_code=EnumCoreErrorCode.DATABASE_OPERATION_ERROR,
|
|
342
|
+
context=context,
|
|
343
|
+
**extra_context,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class RepositoryTimeoutError(RepositoryError):
|
|
348
|
+
"""Raised when a repository query exceeds its timeout.
|
|
349
|
+
|
|
350
|
+
Used when:
|
|
351
|
+
- Query exceeds statement_timeout
|
|
352
|
+
- Connection acquisition times out
|
|
353
|
+
- Transaction times out
|
|
354
|
+
|
|
355
|
+
Timeout errors are retriable - the same query may succeed
|
|
356
|
+
under different load conditions or with adjusted timeouts.
|
|
357
|
+
|
|
358
|
+
Example:
|
|
359
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
360
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
361
|
+
... operation="execute_operation",
|
|
362
|
+
... )
|
|
363
|
+
>>> raise RepositoryTimeoutError(
|
|
364
|
+
... "Query exceeded 30s timeout",
|
|
365
|
+
... op_name="complex_report",
|
|
366
|
+
... table="analytics",
|
|
367
|
+
... timeout_seconds=30.0,
|
|
368
|
+
... sql_fingerprint="SELECT ... FROM analytics ...",
|
|
369
|
+
... context=context,
|
|
370
|
+
... )
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
_default_retriable: bool = True
|
|
374
|
+
|
|
375
|
+
def __init__(
|
|
376
|
+
self,
|
|
377
|
+
message: str,
|
|
378
|
+
*,
|
|
379
|
+
op_name: str | None = None,
|
|
380
|
+
table: str | None = None,
|
|
381
|
+
retriable: bool | None = None,
|
|
382
|
+
sql_fingerprint: str | None = None,
|
|
383
|
+
timeout_seconds: float | None = None,
|
|
384
|
+
context: ModelInfraErrorContext | None = None,
|
|
385
|
+
**extra_context: object,
|
|
386
|
+
) -> None:
|
|
387
|
+
"""Initialize RepositoryTimeoutError.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
message: Human-readable error message
|
|
391
|
+
op_name: Operation name that timed out
|
|
392
|
+
table: Target table (if applicable)
|
|
393
|
+
retriable: Override default (True). Timeout errors are
|
|
394
|
+
generally retriable.
|
|
395
|
+
sql_fingerprint: SQL fingerprint for query tracking
|
|
396
|
+
timeout_seconds: The timeout value that was exceeded
|
|
397
|
+
context: Bundled infrastructure context
|
|
398
|
+
**extra_context: Additional context information
|
|
399
|
+
"""
|
|
400
|
+
if timeout_seconds is not None:
|
|
401
|
+
extra_context["timeout_seconds"] = timeout_seconds
|
|
402
|
+
|
|
403
|
+
# Store for programmatic access
|
|
404
|
+
self.timeout_seconds = timeout_seconds
|
|
405
|
+
|
|
406
|
+
super().__init__(
|
|
407
|
+
message=message,
|
|
408
|
+
op_name=op_name,
|
|
409
|
+
table=table,
|
|
410
|
+
retriable=retriable,
|
|
411
|
+
sql_fingerprint=sql_fingerprint,
|
|
412
|
+
error_code=EnumCoreErrorCode.TIMEOUT_ERROR,
|
|
413
|
+
context=context,
|
|
414
|
+
**extra_context,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
__all__ = [
|
|
419
|
+
"RepositoryContractError",
|
|
420
|
+
"RepositoryError",
|
|
421
|
+
"RepositoryExecutionError",
|
|
422
|
+
"RepositoryTimeoutError",
|
|
423
|
+
"RepositoryValidationError",
|
|
424
|
+
]
|