truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.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.
- 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 +437 -10
- 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 +11 -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.0.dist-info/METADATA +309 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.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.0.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -105,27 +105,18 @@ def _register_default_reporters(registry: ReporterRegistry) -> None:
|
|
|
105
105
|
Args:
|
|
106
106
|
registry: Registry to populate.
|
|
107
107
|
|
|
108
|
-
Registers
|
|
108
|
+
Registers 3 reporters:
|
|
109
109
|
- HTML: Rich visual reports with themes
|
|
110
110
|
- CSV: Spreadsheet-compatible format
|
|
111
111
|
- JSON: Machine-readable structured data
|
|
112
|
-
- Markdown: Documentation-friendly format
|
|
113
|
-
- PDF: Print-ready documents
|
|
114
|
-
- JUnit: CI/CD integration (Jenkins, GitHub Actions, etc.)
|
|
115
112
|
"""
|
|
116
113
|
from .csv_reporter import CSVReporter
|
|
117
114
|
from .html_reporter import HTMLReporter
|
|
118
115
|
from .json_reporter import JSONReporter
|
|
119
|
-
from .junit_reporter import JUnitReporter
|
|
120
|
-
from .markdown_reporter import MarkdownReporter
|
|
121
|
-
from .pdf_reporter import PDFReporter
|
|
122
116
|
|
|
123
117
|
registry.register(ReportFormat.HTML, HTMLReporter)
|
|
124
118
|
registry.register(ReportFormat.CSV, CSVReporter)
|
|
125
119
|
registry.register(ReportFormat.JSON, JSONReporter)
|
|
126
|
-
registry.register(ReportFormat.MARKDOWN, MarkdownReporter)
|
|
127
|
-
registry.register(ReportFormat.PDF, PDFReporter)
|
|
128
|
-
registry.register(ReportFormat.JUNIT, JUnitReporter)
|
|
129
120
|
|
|
130
121
|
logger.debug(f"Registered {len(registry.available_formats)} default reporters")
|
|
131
122
|
|
|
@@ -34,6 +34,8 @@ from .notifications.dispatcher import create_dispatcher
|
|
|
34
34
|
from .services import ValidationService
|
|
35
35
|
from .truthound_adapter import get_adapter
|
|
36
36
|
from .triggers import TriggerFactory, TriggerContext, TriggerEvaluation
|
|
37
|
+
from .schema_watcher import process_due_watchers
|
|
38
|
+
from .tiering import process_tiering_policies
|
|
37
39
|
|
|
38
40
|
logger = logging.getLogger(__name__)
|
|
39
41
|
|
|
@@ -76,6 +78,10 @@ class ValidationScheduler:
|
|
|
76
78
|
DATA_CHANGE_CHECK_INTERVAL_SECONDS = 60 # 1 minute (reduced for better responsiveness)
|
|
77
79
|
# Default per-schedule check interval
|
|
78
80
|
DEFAULT_SCHEDULE_CHECK_INTERVAL_MINUTES = 5
|
|
81
|
+
# Schema watcher check interval (how often to check for due watchers)
|
|
82
|
+
SCHEMA_WATCHER_CHECK_INTERVAL_SECONDS = 10 # Check every 10 seconds for due watchers
|
|
83
|
+
# Storage tiering check interval (default: check every hour)
|
|
84
|
+
TIERING_CHECK_INTERVAL_SECONDS = 3600 # 1 hour
|
|
79
85
|
|
|
80
86
|
def __init__(
|
|
81
87
|
self,
|
|
@@ -99,9 +105,19 @@ class ValidationScheduler:
|
|
|
99
105
|
self._maintenance_cron = maintenance_cron or self.DEFAULT_MAINTENANCE_CRON
|
|
100
106
|
self._maintenance_job_id = "system_maintenance"
|
|
101
107
|
self._data_change_job_id = "data_change_check"
|
|
108
|
+
self._schema_watcher_job_id = "schema_watcher_check"
|
|
102
109
|
self._data_change_check_interval = (
|
|
103
110
|
data_change_check_interval or self.DATA_CHANGE_CHECK_INTERVAL_SECONDS
|
|
104
111
|
)
|
|
112
|
+
self._schema_watcher_check_interval = self.SCHEMA_WATCHER_CHECK_INTERVAL_SECONDS
|
|
113
|
+
|
|
114
|
+
# Tiering state
|
|
115
|
+
self._tiering_job_id = "tiering_policy_check"
|
|
116
|
+
self._tiering_running = False
|
|
117
|
+
self._last_tiering_run: datetime | None = None
|
|
118
|
+
self._tiering_check_count = 0
|
|
119
|
+
self._tiering_processed_count = 0
|
|
120
|
+
self._tiering_check_interval = self.TIERING_CHECK_INTERVAL_SECONDS
|
|
105
121
|
|
|
106
122
|
# Trigger monitoring state
|
|
107
123
|
self._trigger_check_times: dict[str, datetime] = {} # schedule_id -> last_check_at
|
|
@@ -111,6 +127,12 @@ class ValidationScheduler:
|
|
|
111
127
|
self._last_checker_run: datetime | None = None
|
|
112
128
|
self._checker_running = False
|
|
113
129
|
|
|
130
|
+
# Schema watcher monitoring state
|
|
131
|
+
self._last_schema_watcher_run: datetime | None = None
|
|
132
|
+
self._schema_watcher_running = False
|
|
133
|
+
self._schema_watcher_check_count = 0
|
|
134
|
+
self._schema_watcher_processed_count = 0
|
|
135
|
+
|
|
114
136
|
async def start(self) -> None:
|
|
115
137
|
"""Start the scheduler and load existing schedules."""
|
|
116
138
|
logger.info("Starting validation scheduler")
|
|
@@ -124,6 +146,12 @@ class ValidationScheduler:
|
|
|
124
146
|
# Start data change trigger checker
|
|
125
147
|
self._schedule_data_change_checker()
|
|
126
148
|
|
|
149
|
+
# Start schema watcher checker
|
|
150
|
+
self._schedule_schema_watcher_checker()
|
|
151
|
+
|
|
152
|
+
# Start tiering policy checker
|
|
153
|
+
self._schedule_tiering_checker()
|
|
154
|
+
|
|
127
155
|
async def stop(self) -> None:
|
|
128
156
|
"""Stop the scheduler."""
|
|
129
157
|
logger.info("Stopping validation scheduler")
|
|
@@ -500,6 +528,143 @@ class ValidationScheduler:
|
|
|
500
528
|
except Exception as e:
|
|
501
529
|
logger.error(f"Failed to schedule data change checker: {e}")
|
|
502
530
|
|
|
531
|
+
def _schedule_schema_watcher_checker(self) -> None:
|
|
532
|
+
"""Schedule periodic checker for schema watchers."""
|
|
533
|
+
try:
|
|
534
|
+
self._scheduler.add_job(
|
|
535
|
+
self._check_schema_watchers,
|
|
536
|
+
trigger=IntervalTrigger(seconds=self._schema_watcher_check_interval),
|
|
537
|
+
id=self._schema_watcher_job_id,
|
|
538
|
+
name="Schema Watcher Checker",
|
|
539
|
+
replace_existing=True,
|
|
540
|
+
)
|
|
541
|
+
logger.info(
|
|
542
|
+
f"Scheduled schema watcher checker: every {self._schema_watcher_check_interval}s"
|
|
543
|
+
)
|
|
544
|
+
except Exception as e:
|
|
545
|
+
logger.error(f"Failed to schedule schema watcher checker: {e}")
|
|
546
|
+
|
|
547
|
+
async def _check_schema_watchers(self) -> None:
|
|
548
|
+
"""Check all schema watchers that are due for checking.
|
|
549
|
+
|
|
550
|
+
This runs periodically to process watchers whose next_check_at
|
|
551
|
+
timestamp has passed.
|
|
552
|
+
|
|
553
|
+
Features:
|
|
554
|
+
- Processes all due watchers in order
|
|
555
|
+
- Updates watcher state after each check
|
|
556
|
+
- Creates alerts for detected changes
|
|
557
|
+
- Sends notifications if enabled
|
|
558
|
+
"""
|
|
559
|
+
if self._schema_watcher_running:
|
|
560
|
+
logger.debug("Schema watcher check already running, skipping")
|
|
561
|
+
return
|
|
562
|
+
|
|
563
|
+
self._schema_watcher_running = True
|
|
564
|
+
self._last_schema_watcher_run = datetime.utcnow()
|
|
565
|
+
self._schema_watcher_check_count += 1
|
|
566
|
+
logger.debug("Checking schema watchers")
|
|
567
|
+
|
|
568
|
+
try:
|
|
569
|
+
async with get_session() as session:
|
|
570
|
+
processed = await process_due_watchers(session)
|
|
571
|
+
self._schema_watcher_processed_count += processed
|
|
572
|
+
|
|
573
|
+
if processed > 0:
|
|
574
|
+
logger.info(f"Processed {processed} schema watcher(s)")
|
|
575
|
+
except Exception as e:
|
|
576
|
+
logger.error(f"Error checking schema watchers: {e}")
|
|
577
|
+
finally:
|
|
578
|
+
self._schema_watcher_running = False
|
|
579
|
+
|
|
580
|
+
def get_schema_watcher_status(self) -> dict[str, Any]:
|
|
581
|
+
"""Get current schema watcher checker status.
|
|
582
|
+
|
|
583
|
+
Returns:
|
|
584
|
+
Dictionary with schema watcher checker stats.
|
|
585
|
+
"""
|
|
586
|
+
return {
|
|
587
|
+
"enabled": True,
|
|
588
|
+
"checker_running": self._schema_watcher_running,
|
|
589
|
+
"checker_interval_seconds": self._schema_watcher_check_interval,
|
|
590
|
+
"last_checker_run_at": (
|
|
591
|
+
self._last_schema_watcher_run.isoformat()
|
|
592
|
+
if self._last_schema_watcher_run else None
|
|
593
|
+
),
|
|
594
|
+
"total_checks": self._schema_watcher_check_count,
|
|
595
|
+
"total_processed": self._schema_watcher_processed_count,
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
def _schedule_tiering_checker(self) -> None:
|
|
599
|
+
"""Schedule periodic checker for storage tiering policies."""
|
|
600
|
+
try:
|
|
601
|
+
self._scheduler.add_job(
|
|
602
|
+
self._check_tiering_policies,
|
|
603
|
+
trigger=IntervalTrigger(seconds=self._tiering_check_interval),
|
|
604
|
+
id=self._tiering_job_id,
|
|
605
|
+
name="Tiering Policy Checker",
|
|
606
|
+
replace_existing=True,
|
|
607
|
+
)
|
|
608
|
+
logger.info(
|
|
609
|
+
f"Scheduled tiering policy checker: every {self._tiering_check_interval}s"
|
|
610
|
+
)
|
|
611
|
+
except Exception as e:
|
|
612
|
+
logger.error(f"Failed to schedule tiering policy checker: {e}")
|
|
613
|
+
|
|
614
|
+
async def _check_tiering_policies(self) -> None:
|
|
615
|
+
"""Check and execute all active tiering policies.
|
|
616
|
+
|
|
617
|
+
This runs periodically to evaluate tier policies and migrate
|
|
618
|
+
eligible items between storage tiers.
|
|
619
|
+
|
|
620
|
+
Features:
|
|
621
|
+
- Processes all active policies in priority order
|
|
622
|
+
- Records migration history
|
|
623
|
+
- Respects batch size limits from configuration
|
|
624
|
+
"""
|
|
625
|
+
if self._tiering_running:
|
|
626
|
+
logger.debug("Tiering policy check already running, skipping")
|
|
627
|
+
return
|
|
628
|
+
|
|
629
|
+
self._tiering_running = True
|
|
630
|
+
self._last_tiering_run = datetime.utcnow()
|
|
631
|
+
self._tiering_check_count += 1
|
|
632
|
+
logger.debug("Checking tiering policies")
|
|
633
|
+
|
|
634
|
+
try:
|
|
635
|
+
async with get_session() as session:
|
|
636
|
+
results = await process_tiering_policies(session)
|
|
637
|
+
total_migrated = sum(r.items_migrated for r in results)
|
|
638
|
+
self._tiering_processed_count += total_migrated
|
|
639
|
+
|
|
640
|
+
if total_migrated > 0:
|
|
641
|
+
logger.info(
|
|
642
|
+
f"Tiering: migrated {total_migrated} item(s) "
|
|
643
|
+
f"across {len(results)} policy(ies)"
|
|
644
|
+
)
|
|
645
|
+
except Exception as e:
|
|
646
|
+
logger.error(f"Error checking tiering policies: {e}")
|
|
647
|
+
finally:
|
|
648
|
+
self._tiering_running = False
|
|
649
|
+
|
|
650
|
+
def get_tiering_status(self) -> dict[str, Any]:
|
|
651
|
+
"""Get current tiering checker status.
|
|
652
|
+
|
|
653
|
+
Returns:
|
|
654
|
+
Dictionary with tiering checker stats.
|
|
655
|
+
"""
|
|
656
|
+
return {
|
|
657
|
+
"enabled": True,
|
|
658
|
+
"checker_running": self._tiering_running,
|
|
659
|
+
"checker_interval_seconds": self._tiering_check_interval,
|
|
660
|
+
"last_checker_run_at": (
|
|
661
|
+
self._last_tiering_run.isoformat()
|
|
662
|
+
if self._last_tiering_run else None
|
|
663
|
+
),
|
|
664
|
+
"total_checks": self._tiering_check_count,
|
|
665
|
+
"total_migrated": self._tiering_processed_count,
|
|
666
|
+
}
|
|
667
|
+
|
|
503
668
|
async def _check_data_change_triggers(self) -> None:
|
|
504
669
|
"""Check all data change and composite triggers.
|
|
505
670
|
|
|
@@ -84,7 +84,7 @@ class SchemaVersionRepository(BaseRepository[SchemaVersion]):
|
|
|
84
84
|
offset=offset,
|
|
85
85
|
limit=limit,
|
|
86
86
|
filters=[SchemaVersion.source_id == source_id],
|
|
87
|
-
order_by=
|
|
87
|
+
order_by=SchemaVersion.version_number.desc(),
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
async def get_next_version_number(self, source_id: str) -> int:
|
|
@@ -151,7 +151,7 @@ class SchemaChangeRepository(BaseRepository[SchemaChange]):
|
|
|
151
151
|
offset=offset,
|
|
152
152
|
limit=limit,
|
|
153
153
|
filters=[SchemaChange.source_id == source_id],
|
|
154
|
-
order_by=
|
|
154
|
+
order_by=SchemaChange.created_at.desc(),
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
async def get_for_version(
|
|
@@ -167,7 +167,7 @@ class SchemaChangeRepository(BaseRepository[SchemaChange]):
|
|
|
167
167
|
"""
|
|
168
168
|
return await self.list(
|
|
169
169
|
filters=[SchemaChange.to_version_id == to_version_id],
|
|
170
|
-
order_by=
|
|
170
|
+
order_by=SchemaChange.created_at.desc(),
|
|
171
171
|
)
|
|
172
172
|
|
|
173
173
|
async def count_breaking_changes(self, source_id: str) -> int:
|