Небольшие изменения

This commit is contained in:
brusnitsyn
2026-03-13 17:11:39 +09:00
parent c201d36ae6
commit de2dd82fa1
18 changed files with 1140 additions and 491 deletions

View File

@@ -13,27 +13,6 @@ from app.taskiq.broker import refresh_schedules
router = APIRouter(prefix="/api/v1")
@router.post("/migrate/start")
async def start_migration(background_tasks: BackgroundTasks, full_reload: bool = False):
"""Запуск миграции"""
if migrator.is_running:
raise HTTPException(status_code=400, detail="Миграция уже выполняется")
background_tasks.add_task(run_migration_task, full_reload)
return {"message": "Миграция запущена", "full_reload": full_reload}
@router.post("/migrate/stop")
async def stop_migration():
migrator.stop_migration()
return {"message": "Миграция останавливается"}
@router.get("/migrate/status")
async def get_status():
return migrator.get_status()
@router.get("/replication/last")
async def get_last_replication():
"""Получить информацию о последней репликации (максимальное время по всем таблицам)"""
@@ -64,14 +43,14 @@ async def get_tables_status():
}
@router.get("/replication/tables/{table_name}")
async def get_table_status(table_name: str):
@router.get("/replication/tables/{metadata_id}")
async def get_table_status(metadata_id: int):
"""Получить статус конкретной таблицы"""
from app.repository.replication_metadata_repo import replication_metadata_repo
metadata = replication_metadata_repo.get_table_metadata(table_name)
metadata = replication_metadata_repo.get_table_metadata(metadata_id)
if not metadata:
raise HTTPException(status_code=404, detail=f"Таблица {table_name} не найдена")
raise HTTPException(status_code=404, detail=f"Метадата с ID={metadata_id} не найдена")
return {
"table": metadata.table_name,
@@ -85,29 +64,34 @@ async def get_table_status(table_name: str):
}
@router.post("/replication/tables/{table_name}/reset")
async def reset_table(table_name: str):
"""Сбросить состояние таблицы (обнулить last_id и last_sync_time)"""
from app.repository.replication_metadata_repo import replication_metadata_repo
session = replication_metadata_repo.get_session()
@router.post("/replication/tables")
async def add_metadata(
table_name: str = Query(None, description="Наименование таблицы"),
life_table_name: Optional[str] = Query(None, description="Наименование Life таблицы"),
description: Optional[str] = Query(None, description="Описание"),
enabled: bool = Query(True, description="Включено"),
):
"""Добавить метадату"""
try:
metadata = session.query(ReplicationMetadata).filter_by(table_name=table_name).first()
from app.repository.replication_metadata_repo import replication_metadata_repo
metadata = replication_metadata_repo.add_metadata(
table_name=table_name,
life_table_name=life_table_name,
description=description,
enabled=enabled,
)
if metadata:
metadata.last_id = 0
metadata.last_sync_time = datetime(1900, 1, 1)
metadata.total_rows = 0
metadata.last_error = None
metadata.updated_at = datetime.now()
session.commit()
migration_logger.info(f"Сброшено состояние таблицы {table_name}")
return {"message": f"Состояние таблицы {table_name} сброшено"}
return {
"message": f"Метадата для таблицы {metadata.table_name} создана",
"metadata": metadata
}
else:
raise HTTPException(status_code=404, detail=f"Таблица {table_name} не найдена")
finally:
session.close()
raise HTTPException(status_code=500, detail="Ошибка создания метадаты")
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/replication/logs")
async def get_replication_logs(
@@ -146,26 +130,6 @@ async def get_replication_logs(
finally:
session.close()
@router.post("/test-email")
async def test_email():
"""Тест отправки email"""
success = email_sender.send_email(
subject="Тестовое письмо",
body=f"Это тестовое письмо от Migration Service\n\nВремя: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
)
if success:
return {"message": "Тестовое письмо отправлено"}
else:
raise HTTPException(status_code=500, detail="Ошибка отправки письма")
def run_migration_task(full_reload: bool):
try:
migrator.run_migration(full_reload=full_reload)
except Exception as e:
migration_logger.error("Ошибка в фоновой задаче", e)
# ==================== РАСПИСАНИЯ ====================
@router.get("/schedules")
@@ -203,10 +167,10 @@ async def get_next_runs(limit: int = 10):
if time_diff <= 1 and check_weekday in schedule.days_list:
# Получаем статистику таблицы
metadata = replication_metadata_repo.get_table_metadata(schedule.table_name)
metadata = schedule.table
runs.append({
'table': schedule.table_name,
'table': metadata.table_name,
'time': check_time.strftime('%Y-%m-%d %H:%M'),
'day': check_time.strftime('%A'),
'days_schedule': schedule.days_display,
@@ -224,37 +188,37 @@ async def get_next_runs(limit: int = 10):
return runs[:limit]
@router.post("/schedules/run-now")
async def run_scheduled_now(background_tasks: BackgroundTasks):
"""Принудительно запустить все запланированные на текущее время миграции"""
due = scheduler.get_due_tables()
if not due:
return {'message': 'Нет таблиц для миграции в текущее время и день'}
# @router.post("/schedules/run-now")
# async def run_scheduled_now(background_tasks: BackgroundTasks):
# """Принудительно запустить все запланированные на текущее время миграции"""
# due = scheduler.get_due_tables()
# if not due:
# return {'message': 'Нет таблиц для миграции в текущее время и день'}
for schedule in due:
background_tasks.add_task(
run_scheduled_migration,
schedule.table_name,
schedule.full_reload
)
# for schedule in due:
# background_tasks.add_task(
# run_scheduled_migration,
# schedule.table.table_name,
# schedule.full_reload
# )
return {
'message': f'Запущено {len(due)} миграций',
'tables': [
{
'name': s.table_name,
'time': s.schedule_time.strftime("%H:%M"),
'days': s.days_display,
'full_reload': s.full_reload
}
for s in due
]
}
# return {
# 'message': f'Запущено {len(due)} миграций',
# 'tables': [
# {
# 'name': s.table.table_name,
# 'time': s.schedule_time.strftime("%H:%M"),
# 'days': s.days_display,
# 'full_reload': s.full_reload
# }
# for s in due
# ]
# }
@router.post("/schedules/{table_name}")
async def set_schedule(
table_name: str,
metadata_id: int = Query('ID', description="ID метадаты таблицы"),
schedule_time: str = Query("00:00", description="Время в формате HH:MM"),
days: Optional[str] = Query(None, description="Дни недели через запятую: пн,вт,ср,чт,пт,сб,вс"),
full_reload: bool = Query(False, description="Полная перезагрузка"),
@@ -264,8 +228,8 @@ async def set_schedule(
):
"""Добавить новое расписание для таблицы"""
try:
if table_name not in settings.TABLES_TO_COPY:
raise HTTPException(status_code=404, detail=f"Таблица {table_name} не найдена")
# if table_name not in settings.TABLES_TO_COPY:
# raise HTTPException(status_code=404, detail=f"Таблица {table_name} не найдена")
days_list = None
if days:
@@ -274,7 +238,7 @@ async def set_schedule(
from app.repository.replication_metadata_repo import replication_metadata_repo
schedule = replication_metadata_repo.add_schedule(
table_name=table_name,
metadata_id=metadata_id,
schedule_time=schedule_time,
days=days_list,
full_reload=full_reload,
@@ -286,7 +250,7 @@ async def set_schedule(
if schedule:
await refresh_schedules()
return {
"message": f"Расписание добавлено для {table_name} в {schedule_time}",
"message": f"Расписание добавлено",
"schedule": schedule
}
else:
@@ -295,19 +259,25 @@ async def set_schedule(
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/schedules/{table_name}")
async def get_table_schedule(table_name: str):
@router.get("/schedules/{metadata_id}")
async def get_table_schedule(metadata_id: int):
"""Получить расписание для конкретной таблицы"""
schedule = replication_metadata_repo.get_schedule(table_name)
if not schedule:
schedules = replication_metadata_repo.get_schedule(metadata_id)
if not schedules:
raise HTTPException(status_code=404, detail="Расписание не найдено")
# Получаем статистику таблицы
metadata = replication_metadata_repo.get_table_metadata(table_name)
metadata = replication_metadata_repo.get_table_metadata(metadata_id)
result = schedule.to_dict()
result = {}
result['schedules'] = []
for schedule in schedules:
result['schedules'].append(schedule)
if metadata:
result['table_stats'] = {
'table_name': metadata.table_name,
'rows_count': metadata.total_rows,
'last_sync': metadata.last_sync_time.isoformat() if metadata.last_sync_time else None,
'last_id': metadata.last_id
@@ -350,72 +320,71 @@ async def update_schedule(
else:
raise HTTPException(status_code=404, detail=f"Расписание {schedule_id} не найдено")
@router.post("/schedules/{table_name}/disable")
async def disable_schedule(table_name: str):
@router.post("/schedules/{schedule_id}/disable")
async def disable_schedule(schedule_id: int):
"""Отключить расписание"""
success = replication_metadata_repo.disable_schedule(table_name)
success = replication_metadata_repo.disable_schedule(schedule_id)
if success:
await refresh_schedules()
return {'message': f'Расписание для {table_name} отключено'}
return {'message': f'Расписание отключено'}
else:
raise HTTPException(status_code=404, detail=f"Расписание для {table_name} не найдено")
raise HTTPException(status_code=404, detail=f"Расписание с ID={schedule_id} не найдено")
@router.post("/schedules/{table_name}/enable")
async def enable_schedule(table_name: str):
@router.post("/schedules/{schedule_id}/enable")
async def enable_schedule(schedule_id: int):
"""Включить расписание"""
success = replication_metadata_repo.enable_schedule(table_name)
success = replication_metadata_repo.enable_schedule(schedule_id)
if success:
await refresh_schedules()
return {'message': f'Расписание для {table_name} включено'}
return {'message': f'Расписание включено'}
else:
raise HTTPException(status_code=404, detail=f"Расписание для {table_name} не найдено")
raise HTTPException(status_code=404, detail=f"Расписание с ID={schedule_id} не найдено")
# ==================== Фоновые задачи ====================
def run_migration_task(full_reload: bool):
"""Фоновая задача для миграции всех таблиц"""
try:
migrator.run_migration(full_reload=full_reload)
except Exception as e:
migration_logger.error(f"Ошибка в фоновой задаче: {e}")
migration_logger.exception(e)
# def run_migration_task(full_reload: bool):
# """Фоновая задача для миграции всех таблиц"""
# try:
# migrator.run_migration(full_reload=full_reload)
# except Exception as e:
# migration_logger.error(f"Ошибка в фоновой задаче: {e}")
def run_scheduled_migration(table_name: str, full_reload: bool):
"""Фоновая задача для запланированной миграции одной таблицы"""
try:
migration_logger.info(f"Запуск запланированной миграции для {table_name}")
# def run_scheduled_migration(table_name: str, full_reload: bool):
# """Фоновая задача для запланированной миграции одной таблицы"""
# try:
# migration_logger.info(f"Запуск запланированной миграции для {table_name}")
migrator.run_migration(
tables=[table_name],
full_reload=full_reload,
send_email=True
)
# migrator.run_migration(
# tables=[table_name],
# full_reload=full_reload,
# send_email=True
# )
# Обновляем время последнего запуска в расписании
replication_metadata_repo.update_schedule_last_run(table_name)
# # Обновляем время последнего запуска в расписании
# replication_metadata_repo.update_schedule_last_run(table_name)
# Логируем успешный запуск
replication_metadata_repo.log_operation(
table_name=table_name,
operation='SCHEDULED',
records_count=0,
status='SUCCESS'
)
# # Логируем успешный запуск
# replication_metadata_repo.log_operation(
# table_name=table_name,
# operation='SCHEDULED',
# records_count=0,
# status='SUCCESS'
# )
migration_logger.info(f"Запланированная миграция для {table_name} завершена")
# migration_logger.info(f"Запланированная миграция для {table_name} завершена")
except Exception as e:
error_msg = f"Ошибка в запланированной миграции для {table_name}: {e}"
migration_logger.error(error_msg)
migration_logger.exception(e)
# except Exception as e:
# error_msg = f"Ошибка в запланированной миграции для {table_name}: {e}"
# migration_logger.error(error_msg)
# migration_logger.exception(e)
# Логируем ошибку
replication_metadata_repo.log_operation(
table_name=table_name,
operation='SCHEDULED',
records_count=0,
status='ERROR',
error_message=str(e)[:500]
)
# # Логируем ошибку
# replication_metadata_repo.log_operation(
# table_name=table_name,
# operation='SCHEDULED',
# records_count=0,
# status='ERROR',
# error_message=str(e)[:500]
# )