truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.1__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.
- truthound_dashboard/api/alerts.py +75 -86
- truthound_dashboard/api/anomaly.py +7 -13
- truthound_dashboard/api/cross_alerts.py +38 -52
- truthound_dashboard/api/drift.py +49 -59
- truthound_dashboard/api/drift_monitor.py +234 -79
- truthound_dashboard/api/enterprise_sampling.py +498 -0
- truthound_dashboard/api/history.py +57 -5
- truthound_dashboard/api/lineage.py +3 -48
- truthound_dashboard/api/maintenance.py +104 -49
- truthound_dashboard/api/mask.py +1 -2
- truthound_dashboard/api/middleware.py +2 -1
- truthound_dashboard/api/model_monitoring.py +435 -311
- truthound_dashboard/api/notifications.py +227 -191
- truthound_dashboard/api/notifications_advanced.py +21 -20
- truthound_dashboard/api/observability.py +586 -0
- truthound_dashboard/api/plugins.py +2 -433
- truthound_dashboard/api/profile.py +199 -37
- truthound_dashboard/api/quality_reporter.py +701 -0
- truthound_dashboard/api/reports.py +7 -16
- truthound_dashboard/api/router.py +66 -0
- truthound_dashboard/api/rule_suggestions.py +5 -5
- truthound_dashboard/api/scan.py +17 -19
- truthound_dashboard/api/schedules.py +85 -50
- truthound_dashboard/api/schema_evolution.py +6 -6
- truthound_dashboard/api/schema_watcher.py +667 -0
- truthound_dashboard/api/sources.py +98 -27
- truthound_dashboard/api/tiering.py +1323 -0
- truthound_dashboard/api/triggers.py +14 -11
- truthound_dashboard/api/validations.py +12 -11
- truthound_dashboard/api/versioning.py +1 -6
- truthound_dashboard/core/__init__.py +129 -3
- truthound_dashboard/core/actions/__init__.py +62 -0
- truthound_dashboard/core/actions/custom.py +426 -0
- truthound_dashboard/core/actions/notifications.py +910 -0
- truthound_dashboard/core/actions/storage.py +472 -0
- truthound_dashboard/core/actions/webhook.py +281 -0
- truthound_dashboard/core/anomaly.py +262 -67
- truthound_dashboard/core/anomaly_explainer.py +4 -3
- truthound_dashboard/core/backends/__init__.py +67 -0
- truthound_dashboard/core/backends/base.py +299 -0
- truthound_dashboard/core/backends/errors.py +191 -0
- truthound_dashboard/core/backends/factory.py +423 -0
- truthound_dashboard/core/backends/mock_backend.py +451 -0
- truthound_dashboard/core/backends/truthound_backend.py +718 -0
- truthound_dashboard/core/checkpoint/__init__.py +87 -0
- truthound_dashboard/core/checkpoint/adapters.py +814 -0
- truthound_dashboard/core/checkpoint/checkpoint.py +491 -0
- truthound_dashboard/core/checkpoint/runner.py +270 -0
- truthound_dashboard/core/connections.py +645 -23
- truthound_dashboard/core/converters/__init__.py +14 -0
- truthound_dashboard/core/converters/truthound.py +620 -0
- truthound_dashboard/core/cross_alerts.py +540 -320
- truthound_dashboard/core/datasource_factory.py +1672 -0
- truthound_dashboard/core/drift_monitor.py +216 -20
- truthound_dashboard/core/enterprise_sampling.py +1291 -0
- truthound_dashboard/core/interfaces/__init__.py +225 -0
- truthound_dashboard/core/interfaces/actions.py +652 -0
- truthound_dashboard/core/interfaces/base.py +247 -0
- truthound_dashboard/core/interfaces/checkpoint.py +676 -0
- truthound_dashboard/core/interfaces/protocols.py +664 -0
- truthound_dashboard/core/interfaces/reporters.py +650 -0
- truthound_dashboard/core/interfaces/routing.py +646 -0
- truthound_dashboard/core/interfaces/triggers.py +619 -0
- truthound_dashboard/core/lineage.py +407 -71
- truthound_dashboard/core/model_monitoring.py +431 -3
- truthound_dashboard/core/notifications/base.py +4 -0
- truthound_dashboard/core/notifications/channels.py +501 -1203
- truthound_dashboard/core/notifications/deduplication/__init__.py +81 -115
- truthound_dashboard/core/notifications/deduplication/service.py +131 -348
- truthound_dashboard/core/notifications/dispatcher.py +202 -11
- truthound_dashboard/core/notifications/escalation/__init__.py +119 -106
- truthound_dashboard/core/notifications/escalation/engine.py +168 -358
- truthound_dashboard/core/notifications/routing/__init__.py +88 -128
- truthound_dashboard/core/notifications/routing/engine.py +90 -317
- truthound_dashboard/core/notifications/stats_aggregator.py +246 -1
- truthound_dashboard/core/notifications/throttling/__init__.py +67 -50
- truthound_dashboard/core/notifications/throttling/builder.py +117 -255
- truthound_dashboard/core/notifications/truthound_adapter.py +842 -0
- truthound_dashboard/core/phase5/collaboration.py +1 -1
- truthound_dashboard/core/plugins/lifecycle/__init__.py +0 -13
- truthound_dashboard/core/quality_reporter.py +1359 -0
- truthound_dashboard/core/report_history.py +0 -6
- truthound_dashboard/core/reporters/__init__.py +175 -14
- truthound_dashboard/core/reporters/adapters.py +943 -0
- truthound_dashboard/core/reporters/base.py +0 -3
- truthound_dashboard/core/reporters/builtin/__init__.py +18 -0
- truthound_dashboard/core/reporters/builtin/csv_reporter.py +111 -0
- truthound_dashboard/core/reporters/builtin/html_reporter.py +270 -0
- truthound_dashboard/core/reporters/builtin/json_reporter.py +127 -0
- truthound_dashboard/core/reporters/compat.py +266 -0
- truthound_dashboard/core/reporters/csv_reporter.py +2 -35
- truthound_dashboard/core/reporters/factory.py +526 -0
- truthound_dashboard/core/reporters/interfaces.py +745 -0
- truthound_dashboard/core/reporters/registry.py +1 -10
- truthound_dashboard/core/scheduler.py +165 -0
- truthound_dashboard/core/schema_evolution.py +3 -3
- truthound_dashboard/core/schema_watcher.py +1528 -0
- truthound_dashboard/core/services.py +595 -76
- truthound_dashboard/core/store_manager.py +810 -0
- truthound_dashboard/core/streaming_anomaly.py +169 -4
- truthound_dashboard/core/tiering.py +1309 -0
- truthound_dashboard/core/triggers/evaluators.py +178 -8
- truthound_dashboard/core/truthound_adapter.py +2620 -197
- truthound_dashboard/core/unified_alerts.py +23 -20
- truthound_dashboard/db/__init__.py +8 -0
- truthound_dashboard/db/database.py +8 -2
- truthound_dashboard/db/models.py +944 -25
- truthound_dashboard/db/repository.py +2 -0
- truthound_dashboard/main.py +15 -0
- truthound_dashboard/schemas/__init__.py +177 -16
- truthound_dashboard/schemas/base.py +44 -23
- truthound_dashboard/schemas/collaboration.py +19 -6
- truthound_dashboard/schemas/cross_alerts.py +19 -3
- truthound_dashboard/schemas/drift.py +61 -55
- truthound_dashboard/schemas/drift_monitor.py +67 -23
- truthound_dashboard/schemas/enterprise_sampling.py +653 -0
- truthound_dashboard/schemas/lineage.py +0 -33
- truthound_dashboard/schemas/mask.py +10 -8
- truthound_dashboard/schemas/model_monitoring.py +89 -10
- truthound_dashboard/schemas/notifications_advanced.py +13 -0
- truthound_dashboard/schemas/observability.py +453 -0
- truthound_dashboard/schemas/plugins.py +0 -280
- truthound_dashboard/schemas/profile.py +154 -247
- truthound_dashboard/schemas/quality_reporter.py +403 -0
- truthound_dashboard/schemas/reports.py +2 -2
- truthound_dashboard/schemas/rule_suggestion.py +8 -1
- truthound_dashboard/schemas/scan.py +4 -24
- truthound_dashboard/schemas/schedule.py +11 -3
- truthound_dashboard/schemas/schema_watcher.py +727 -0
- truthound_dashboard/schemas/source.py +17 -2
- truthound_dashboard/schemas/tiering.py +822 -0
- truthound_dashboard/schemas/triggers.py +16 -0
- truthound_dashboard/schemas/unified_alerts.py +7 -0
- truthound_dashboard/schemas/validation.py +0 -13
- truthound_dashboard/schemas/validators/base.py +41 -21
- truthound_dashboard/schemas/validators/business_rule_validators.py +244 -0
- truthound_dashboard/schemas/validators/localization_validators.py +273 -0
- truthound_dashboard/schemas/validators/ml_feature_validators.py +308 -0
- truthound_dashboard/schemas/validators/profiling_validators.py +275 -0
- truthound_dashboard/schemas/validators/referential_validators.py +312 -0
- truthound_dashboard/schemas/validators/registry.py +93 -8
- truthound_dashboard/schemas/validators/timeseries_validators.py +389 -0
- truthound_dashboard/schemas/versioning.py +1 -6
- truthound_dashboard/static/index.html +2 -2
- truthound_dashboard-1.5.1.dist-info/METADATA +312 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/RECORD +149 -148
- truthound_dashboard/core/plugins/hooks/__init__.py +0 -63
- truthound_dashboard/core/plugins/hooks/decorators.py +0 -367
- truthound_dashboard/core/plugins/hooks/manager.py +0 -403
- truthound_dashboard/core/plugins/hooks/protocols.py +0 -265
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +0 -584
- truthound_dashboard/core/reporters/junit_reporter.py +0 -233
- truthound_dashboard/core/reporters/markdown_reporter.py +0 -207
- truthound_dashboard/core/reporters/pdf_reporter.py +0 -209
- truthound_dashboard/static/assets/_baseUniq-BcrSP13d.js +0 -1
- truthound_dashboard/static/assets/arc-DlYjKwIL.js +0 -1
- truthound_dashboard/static/assets/architectureDiagram-VXUJARFQ-Bb2drbQM.js +0 -36
- truthound_dashboard/static/assets/blockDiagram-VD42YOAC-BlsPG1CH.js +0 -122
- truthound_dashboard/static/assets/c4Diagram-YG6GDRKO-B9JdUoaC.js +0 -10
- truthound_dashboard/static/assets/channel-Q6mHF1Hd.js +0 -1
- truthound_dashboard/static/assets/chunk-4BX2VUAB-DmyoPVuJ.js +0 -1
- truthound_dashboard/static/assets/chunk-55IACEB6-Bcz6Siv8.js +0 -1
- truthound_dashboard/static/assets/chunk-B4BG7PRW-Br3G5Rum.js +0 -165
- truthound_dashboard/static/assets/chunk-DI55MBZ5-DuM9c23u.js +0 -220
- truthound_dashboard/static/assets/chunk-FMBD7UC4-DNU-5mvT.js +0 -15
- truthound_dashboard/static/assets/chunk-QN33PNHL-Im2yNcmS.js +0 -1
- truthound_dashboard/static/assets/chunk-QZHKN3VN-kZr8XFm1.js +0 -1
- truthound_dashboard/static/assets/chunk-TZMSLE5B-Q__360q_.js +0 -1
- truthound_dashboard/static/assets/classDiagram-2ON5EDUG-vtixxUyK.js +0 -1
- truthound_dashboard/static/assets/classDiagram-v2-WZHVMYZB-vtixxUyK.js +0 -1
- truthound_dashboard/static/assets/clone-BOt2LwD0.js +0 -1
- truthound_dashboard/static/assets/cose-bilkent-S5V4N54A-CBDw6iac.js +0 -1
- truthound_dashboard/static/assets/dagre-6UL2VRFP-XdKqmmY9.js +0 -4
- truthound_dashboard/static/assets/diagram-PSM6KHXK-DAZ8nx9V.js +0 -24
- truthound_dashboard/static/assets/diagram-QEK2KX5R-BRvDTbGD.js +0 -43
- truthound_dashboard/static/assets/diagram-S2PKOQOG-bQcczUkl.js +0 -24
- truthound_dashboard/static/assets/erDiagram-Q2GNP2WA-DPje7VMN.js +0 -60
- truthound_dashboard/static/assets/flowDiagram-NV44I4VS-B7BVtFVS.js +0 -162
- truthound_dashboard/static/assets/ganttDiagram-JELNMOA3-D6WKSS7U.js +0 -267
- truthound_dashboard/static/assets/gitGraphDiagram-NY62KEGX-D3vtVd3y.js +0 -65
- truthound_dashboard/static/assets/graph-BKgNKZVp.js +0 -1
- truthound_dashboard/static/assets/index-C6JSrkHo.css +0 -1
- truthound_dashboard/static/assets/index-DkU82VsU.js +0 -1800
- truthound_dashboard/static/assets/infoDiagram-WHAUD3N6-DnNCT429.js +0 -2
- truthound_dashboard/static/assets/journeyDiagram-XKPGCS4Q-DGiMozqS.js +0 -139
- truthound_dashboard/static/assets/kanban-definition-3W4ZIXB7-BV2gUgli.js +0 -89
- truthound_dashboard/static/assets/katex-Cu_Erd72.js +0 -261
- truthound_dashboard/static/assets/layout-DI2MfQ5G.js +0 -1
- truthound_dashboard/static/assets/min-DYdgXVcT.js +0 -1
- truthound_dashboard/static/assets/mindmap-definition-VGOIOE7T-C7x4ruxz.js +0 -68
- truthound_dashboard/static/assets/pieDiagram-ADFJNKIX-CAJaAB9f.js +0 -30
- truthound_dashboard/static/assets/quadrantDiagram-AYHSOK5B-DeqwDI46.js +0 -7
- truthound_dashboard/static/assets/requirementDiagram-UZGBJVZJ-e3XDpZIM.js +0 -64
- truthound_dashboard/static/assets/sankeyDiagram-TZEHDZUN-CNnAv5Ux.js +0 -10
- truthound_dashboard/static/assets/sequenceDiagram-WL72ISMW-Dsne-Of3.js +0 -145
- truthound_dashboard/static/assets/stateDiagram-FKZM4ZOC-Ee0sQXyb.js +0 -1
- truthound_dashboard/static/assets/stateDiagram-v2-4FDKWEC3-B26KqW_W.js +0 -1
- truthound_dashboard/static/assets/timeline-definition-IT6M3QCI-DZYi2yl3.js +0 -61
- truthound_dashboard/static/assets/treemap-KMMF4GRG-CY3f8In2.js +0 -128
- truthound_dashboard/static/assets/unmerged_dictionaries-Dd7xcPWG.js +0 -1
- truthound_dashboard/static/assets/xychartDiagram-PRI3JC2R-CS7fydZZ.js +0 -7
- truthound_dashboard-1.4.4.dist-info/METADATA +0 -507
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Checkpoint runner for managing and executing checkpoints.
|
|
2
|
+
|
|
3
|
+
Provides the CheckpointRunner class for registering, managing,
|
|
4
|
+
and executing multiple checkpoints.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from truthound_dashboard.core.interfaces.checkpoint import (
|
|
14
|
+
CheckpointProtocol,
|
|
15
|
+
CheckpointResult,
|
|
16
|
+
CheckpointRunnerProtocol,
|
|
17
|
+
CheckpointStatus,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CheckpointRunner(CheckpointRunnerProtocol):
|
|
24
|
+
"""Runner for managing and executing checkpoints.
|
|
25
|
+
|
|
26
|
+
Provides a central registry for checkpoints and methods for
|
|
27
|
+
running them individually or in batch.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
runner = CheckpointRunner()
|
|
31
|
+
|
|
32
|
+
# Register checkpoints
|
|
33
|
+
runner.register(orders_checkpoint)
|
|
34
|
+
runner.register(customers_checkpoint)
|
|
35
|
+
|
|
36
|
+
# Run a specific checkpoint
|
|
37
|
+
result = await runner.run("daily_orders")
|
|
38
|
+
|
|
39
|
+
# Run all enabled checkpoints
|
|
40
|
+
results = await runner.run_all(parallel=True)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, max_workers: int = 4) -> None:
|
|
44
|
+
"""Initialize runner.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
max_workers: Max parallel workers for run_all.
|
|
48
|
+
"""
|
|
49
|
+
self._checkpoints: dict[str, CheckpointProtocol] = {}
|
|
50
|
+
self._max_workers = max_workers
|
|
51
|
+
|
|
52
|
+
def register(self, checkpoint: CheckpointProtocol) -> None:
|
|
53
|
+
"""Register a checkpoint.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
checkpoint: Checkpoint to register.
|
|
57
|
+
"""
|
|
58
|
+
self._checkpoints[checkpoint.name] = checkpoint
|
|
59
|
+
logger.info(f"Registered checkpoint: {checkpoint.name}")
|
|
60
|
+
|
|
61
|
+
def unregister(self, name: str) -> bool:
|
|
62
|
+
"""Unregister a checkpoint by name.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
name: Checkpoint name.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
True if checkpoint was unregistered.
|
|
69
|
+
"""
|
|
70
|
+
if name in self._checkpoints:
|
|
71
|
+
del self._checkpoints[name]
|
|
72
|
+
logger.info(f"Unregistered checkpoint: {name}")
|
|
73
|
+
return True
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
def get(self, name: str) -> CheckpointProtocol | None:
|
|
77
|
+
"""Get a checkpoint by name.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
name: Checkpoint name.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Checkpoint or None if not found.
|
|
84
|
+
"""
|
|
85
|
+
return self._checkpoints.get(name)
|
|
86
|
+
|
|
87
|
+
def list_checkpoints(self) -> list[str]:
|
|
88
|
+
"""List all registered checkpoint names.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of checkpoint names.
|
|
92
|
+
"""
|
|
93
|
+
return list(self._checkpoints.keys())
|
|
94
|
+
|
|
95
|
+
def get_all(self) -> list[CheckpointProtocol]:
|
|
96
|
+
"""Get all registered checkpoints.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
List of checkpoints.
|
|
100
|
+
"""
|
|
101
|
+
return list(self._checkpoints.values())
|
|
102
|
+
|
|
103
|
+
async def run(
|
|
104
|
+
self,
|
|
105
|
+
name: str,
|
|
106
|
+
trigger_context: dict[str, Any] | None = None,
|
|
107
|
+
) -> CheckpointResult:
|
|
108
|
+
"""Run a checkpoint by name.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
name: Checkpoint name.
|
|
112
|
+
trigger_context: Optional trigger context.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Checkpoint result.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
KeyError: If checkpoint not found.
|
|
119
|
+
"""
|
|
120
|
+
checkpoint = self.get(name)
|
|
121
|
+
if checkpoint is None:
|
|
122
|
+
raise KeyError(f"Checkpoint not found: {name}")
|
|
123
|
+
|
|
124
|
+
return await checkpoint.run(trigger_context=trigger_context)
|
|
125
|
+
|
|
126
|
+
async def run_all(
|
|
127
|
+
self,
|
|
128
|
+
parallel: bool = False,
|
|
129
|
+
max_workers: int | None = None,
|
|
130
|
+
filter_enabled: bool = True,
|
|
131
|
+
) -> list[CheckpointResult]:
|
|
132
|
+
"""Run all registered checkpoints.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
parallel: Run in parallel.
|
|
136
|
+
max_workers: Max parallel workers (uses instance default if None).
|
|
137
|
+
filter_enabled: Only run enabled checkpoints.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
List of checkpoint results.
|
|
141
|
+
"""
|
|
142
|
+
max_workers = max_workers or self._max_workers
|
|
143
|
+
|
|
144
|
+
# Filter checkpoints
|
|
145
|
+
checkpoints = self.get_all()
|
|
146
|
+
if filter_enabled:
|
|
147
|
+
checkpoints = [cp for cp in checkpoints if cp.config.enabled]
|
|
148
|
+
|
|
149
|
+
if not checkpoints:
|
|
150
|
+
logger.info("No checkpoints to run")
|
|
151
|
+
return []
|
|
152
|
+
|
|
153
|
+
logger.info(f"Running {len(checkpoints)} checkpoints (parallel={parallel})")
|
|
154
|
+
|
|
155
|
+
if parallel:
|
|
156
|
+
return await self._run_parallel(checkpoints, max_workers)
|
|
157
|
+
else:
|
|
158
|
+
return await self._run_sequential(checkpoints)
|
|
159
|
+
|
|
160
|
+
async def _run_sequential(
|
|
161
|
+
self, checkpoints: list[CheckpointProtocol]
|
|
162
|
+
) -> list[CheckpointResult]:
|
|
163
|
+
"""Run checkpoints sequentially.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
checkpoints: Checkpoints to run.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
List of results.
|
|
170
|
+
"""
|
|
171
|
+
results: list[CheckpointResult] = []
|
|
172
|
+
for checkpoint in checkpoints:
|
|
173
|
+
try:
|
|
174
|
+
result = await checkpoint.run()
|
|
175
|
+
results.append(result)
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.error(f"Checkpoint failed: {checkpoint.name} error={str(e)}")
|
|
178
|
+
results.append(CheckpointResult(
|
|
179
|
+
checkpoint_name=checkpoint.name,
|
|
180
|
+
run_id="",
|
|
181
|
+
status=CheckpointStatus.ERROR,
|
|
182
|
+
error_message=str(e),
|
|
183
|
+
))
|
|
184
|
+
return results
|
|
185
|
+
|
|
186
|
+
async def _run_parallel(
|
|
187
|
+
self,
|
|
188
|
+
checkpoints: list[CheckpointProtocol],
|
|
189
|
+
max_workers: int,
|
|
190
|
+
) -> list[CheckpointResult]:
|
|
191
|
+
"""Run checkpoints in parallel with semaphore.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
checkpoints: Checkpoints to run.
|
|
195
|
+
max_workers: Max concurrent executions.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
List of results.
|
|
199
|
+
"""
|
|
200
|
+
semaphore = asyncio.Semaphore(max_workers)
|
|
201
|
+
|
|
202
|
+
async def run_with_semaphore(cp: CheckpointProtocol) -> CheckpointResult:
|
|
203
|
+
async with semaphore:
|
|
204
|
+
try:
|
|
205
|
+
return await cp.run()
|
|
206
|
+
except Exception as e:
|
|
207
|
+
logger.error(f"Checkpoint failed: {cp.name} error={str(e)}")
|
|
208
|
+
return CheckpointResult(
|
|
209
|
+
checkpoint_name=cp.name,
|
|
210
|
+
run_id="",
|
|
211
|
+
status=CheckpointStatus.ERROR,
|
|
212
|
+
error_message=str(e),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
results = await asyncio.gather(
|
|
216
|
+
*[run_with_semaphore(cp) for cp in checkpoints]
|
|
217
|
+
)
|
|
218
|
+
return list(results)
|
|
219
|
+
|
|
220
|
+
async def run_by_tag(
|
|
221
|
+
self,
|
|
222
|
+
tag_key: str,
|
|
223
|
+
tag_value: str,
|
|
224
|
+
parallel: bool = False,
|
|
225
|
+
) -> list[CheckpointResult]:
|
|
226
|
+
"""Run checkpoints matching a tag.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
tag_key: Tag key to match.
|
|
230
|
+
tag_value: Tag value to match.
|
|
231
|
+
parallel: Run in parallel.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
List of checkpoint results.
|
|
235
|
+
"""
|
|
236
|
+
checkpoints = [
|
|
237
|
+
cp for cp in self.get_all()
|
|
238
|
+
if cp.config.tags.get(tag_key) == tag_value and cp.config.enabled
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
if not checkpoints:
|
|
242
|
+
logger.info(f"No checkpoints found with tag {tag_key}={tag_value}")
|
|
243
|
+
return []
|
|
244
|
+
|
|
245
|
+
if parallel:
|
|
246
|
+
return await self._run_parallel(checkpoints, self._max_workers)
|
|
247
|
+
else:
|
|
248
|
+
return await self._run_sequential(checkpoints)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# Global runner instance
|
|
252
|
+
_runner: CheckpointRunner | None = None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def get_checkpoint_runner() -> CheckpointRunner:
|
|
256
|
+
"""Get the global checkpoint runner.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Global CheckpointRunner instance.
|
|
260
|
+
"""
|
|
261
|
+
global _runner
|
|
262
|
+
if _runner is None:
|
|
263
|
+
_runner = CheckpointRunner()
|
|
264
|
+
return _runner
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def reset_checkpoint_runner() -> None:
|
|
268
|
+
"""Reset the global checkpoint runner (for testing)."""
|
|
269
|
+
global _runner
|
|
270
|
+
_runner = None
|