feat(HEL-435): 盘后未出数时晚间自动重试并提供安全补跑
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -22,6 +22,8 @@ LOGGER = get_logger()
|
||||
HARD_DATASETS = {"daily", "valuation", "index_daily"}
|
||||
SOFT_DATASETS = {"moneyflow", "auction"}
|
||||
OFFICIAL_DATASETS = HARD_DATASETS | SOFT_DATASETS
|
||||
EOD_A_DATASETS = ("daily", "valuation", "moneyflow", "auction")
|
||||
EOD_B_DATASETS = ("index_daily",)
|
||||
EMPTY_BATCH_ERROR = "empty official batch: 0 valid rows"
|
||||
|
||||
STAGING_INSERT = {
|
||||
@@ -379,14 +381,62 @@ class Pipeline:
|
||||
self._set_batch(batch_id, dataset, trade_date, "failed", 1, error=str(exc), finished=True)
|
||||
raise
|
||||
|
||||
def missing_official_datasets(self, trade_date: str) -> list[str]:
|
||||
"""Official datasets without an active publication for the date."""
|
||||
day = yyyymmdd(trade_date)
|
||||
placeholders = ",".join("?" for _ in OFFICIAL_DATASETS)
|
||||
rows = self.db.fetchall(
|
||||
f"SELECT dataset FROM publications WHERE trade_date = ? AND dataset IN ({placeholders})",
|
||||
(day, *sorted(OFFICIAL_DATASETS)),
|
||||
)
|
||||
published = {str(row["dataset"]) for row in rows}
|
||||
return [dataset for dataset in sorted(OFFICIAL_DATASETS) if dataset not in published]
|
||||
|
||||
def run_eod_missing(self, trade_date: str) -> dict[str, Any]:
|
||||
"""Fetch/publish every official dataset still missing for the date.
|
||||
|
||||
Idempotent: datasets with an existing publication are skipped, so
|
||||
repeats never overwrite the current official batch. Per-dataset
|
||||
failures are collected instead of aborting the remaining datasets.
|
||||
"""
|
||||
return self._run_eod_datasets(tuple(sorted(OFFICIAL_DATASETS)), trade_date)
|
||||
|
||||
def run_eod_batch_a(self, trade_date: str) -> dict[str, Any]:
|
||||
results = {}
|
||||
for dataset in ("daily", "valuation", "moneyflow", "auction"):
|
||||
results[dataset] = self.run_dataset(dataset, trade_date)
|
||||
return results
|
||||
return self._run_eod_datasets(EOD_A_DATASETS, trade_date)
|
||||
|
||||
def run_eod_batch_b(self, trade_date: str) -> dict[str, Any]:
|
||||
return {"index_daily": self.run_dataset("index_daily", trade_date)}
|
||||
return self._run_eod_datasets(EOD_B_DATASETS, trade_date)
|
||||
|
||||
def _run_eod_datasets(self, datasets: tuple[str, ...], trade_date: str) -> dict[str, Any]:
|
||||
day = yyyymmdd(trade_date)
|
||||
results: dict[str, Any] = {}
|
||||
for dataset in datasets:
|
||||
if self.active_batch(dataset, day) is not None:
|
||||
results[dataset] = {
|
||||
"dataset": dataset,
|
||||
"trade_date": day,
|
||||
"state": "skipped",
|
||||
"reason": "already_published",
|
||||
}
|
||||
continue
|
||||
try:
|
||||
results[dataset] = self.run_dataset(dataset, day)
|
||||
except Exception as exc:
|
||||
results[dataset] = {
|
||||
"dataset": dataset,
|
||||
"trade_date": day,
|
||||
"state": "failed",
|
||||
"error": str(exc),
|
||||
}
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def eod_failures(results: dict[str, Any]) -> list[str]:
|
||||
return [
|
||||
f"{name}: {item.get('error')}"
|
||||
for name, item in results.items()
|
||||
if isinstance(item, dict) and item.get("state") == "failed"
|
||||
]
|
||||
|
||||
def validate(self, dataset: str, batch_id: str, trade_date: str, rows: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
quality = self.settings.quality
|
||||
|
||||
Reference in New Issue
Block a user