|
5 | 5 | from datetime import datetime, timezone |
6 | 6 | from typing import TYPE_CHECKING, Any, Iterable |
7 | 7 |
|
8 | | -from sqlalchemy import bindparam, case, delete, func, insert, select, update |
| 8 | +from sqlalchemy import bindparam, case, delete, func, insert, select, text, update |
9 | 9 |
|
10 | 10 | if TYPE_CHECKING: |
11 | 11 | from sqlalchemy.sql.elements import BindParameter |
12 | 12 |
|
| 13 | +from DIRAC.WorkloadManagementSystem.Client import JobStatus |
| 14 | + |
13 | 15 | from diracx.core.exceptions import InvalidQueryError |
14 | 16 | from diracx.core.models import JobCommand, SearchSpec, SortSpec |
15 | 17 |
|
@@ -333,3 +335,60 @@ async def get_job_commands(self, job_ids: Iterable[int]) -> list[JobCommand]: |
333 | 335 | JobCommand(job_id=cmd.JobID, command=cmd.Command, arguments=cmd.Arguments) |
334 | 336 | for cmd in commands |
335 | 337 | ] |
| 338 | + |
| 339 | + async def fill_jobs_history_summary(self): |
| 340 | + """Fill the JobsHistorySummary table with the summary of the jobs in a final state.""" |
| 341 | + # Create the staging table |
| 342 | + dialect = self.conn.dialect |
| 343 | + if dialect == "mysql": |
| 344 | + create_staging_table_sql = "CREATE TABLE IF NOT EXISTS JobsHistorySummary_staging LIKE JobsHistorySummary" |
| 345 | + elif dialect == "postgresql": |
| 346 | + create_staging_table_sql = ( |
| 347 | + "CREATE TABLE IF NOT EXISTS JobsHistorySummary_staging " |
| 348 | + "(LIKE JobsHistorySummary INCLUDING ALL)" |
| 349 | + ) |
| 350 | + elif dialect == "sqlite": |
| 351 | + create_staging_table_sql = "CREATE TABLE IF NOT EXISTS JobsHistorySummary_staging AS JobsHistorySummary" |
| 352 | + await self.conn.execute(text(create_staging_table_sql)) |
| 353 | + |
| 354 | + if dialect == "mysql": |
| 355 | + current_date_expr = "UTC_DATE()" |
| 356 | + elif dialect == "postgresql": |
| 357 | + current_date_expr = "CURRENT_DATE" |
| 358 | + elif dialect == "sqlite": |
| 359 | + current_date_expr = "DATE('now')" |
| 360 | + else: |
| 361 | + raise ValueError(f"Unsupported DB dialect: {dialect}") |
| 362 | + |
| 363 | + # Columns for grouping |
| 364 | + def_columns = "Status, Site, Owner, OwnerGroup, JobGroup, JobType, ApplicationStatus, MinorStatus" |
| 365 | + agg_columns = "COUNT(JobID), SUM(RescheduleCounter)" |
| 366 | + |
| 367 | + # Final states list |
| 368 | + final_states = JobStatus.JOB_FINAL_STATES + JobStatus.JOB_REALLY_FINAL_STATES |
| 369 | + final_states_sql = ", ".join(f"'{state}'" for state in final_states) |
| 370 | + |
| 371 | + # Build SQL statement |
| 372 | + insert_sql = f""" |
| 373 | + INSERT INTO JobsHistorySummary_staging |
| 374 | + SELECT {def_columns}, {agg_columns} |
| 375 | + FROM Jobs |
| 376 | + WHERE Status IN ({final_states_sql}) |
| 377 | + AND LastUpdateTime < {current_date_expr} |
| 378 | + GROUP BY {def_columns} |
| 379 | + """ # noqa: S608 |
| 380 | + await self.conn.execute(text(insert_sql)) |
| 381 | + |
| 382 | + stmts = [] |
| 383 | + |
| 384 | + if dialect in {"mysql", "sqlite", "postgresql"}: |
| 385 | + stmts = [ |
| 386 | + "ALTER TABLE JobsHistorySummary RENAME TO JobsHistorySummary_old;", |
| 387 | + "ALTER TABLE JobsHistorySummary_staging RENAME TO JobsHistorySummary;", |
| 388 | + "DROP TABLE JobsHistorySummary_old;", |
| 389 | + ] |
| 390 | + else: |
| 391 | + raise ValueError(f"Unsupported DB dialect: {dialect}") |
| 392 | + |
| 393 | + for stmt in stmts: |
| 394 | + await self.conn.execute(text(stmt)) |
0 commit comments