Skip to content

Commit d59ea6b

Browse files
remyluslosiusclaude
andcommitted
fix: complete scheduler endpoint implementation for frontend compatibility
- Add missing PUT /api/system/scheduler endpoint for interval updates - Fix response model to include 'enabled' and 'interval_minutes' fields - Update scheduler start endpoint to accept and use interval_minutes parameter - Fix import issue: use periodic_host_monitoring instead of monitor_all_hosts - Add proper request models for scheduler endpoints - Enable dynamic interval updates while scheduler is running Resolves 404 errors and ensures frontend-backend API compatibility. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent cc318b1 commit d59ea6b

1 file changed

Lines changed: 93 additions & 5 deletions

File tree

backend/app/routes/system_settings_unified.py

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,24 @@ async def delete_system_credential(
527527

528528
# Scheduler endpoints for host monitoring
529529
class SchedulerStatus(BaseModel):
530+
enabled: bool
531+
interval_minutes: int
530532
status: str # "running", "stopped", "error"
531-
jobs: List[dict] = []
533+
jobs: Optional[List[dict]] = []
532534
uptime: Optional[str] = None
533535

534536

535-
# Global scheduler instance
537+
class SchedulerStartRequest(BaseModel):
538+
interval_minutes: int = 5
539+
540+
541+
class SchedulerUpdateRequest(BaseModel):
542+
interval_minutes: int
543+
544+
545+
# Global scheduler instance and settings
536546
_scheduler = None
547+
_scheduler_interval = 5 # Default 5 minutes
537548

538549

539550
def get_scheduler():
@@ -555,6 +566,8 @@ async def get_scheduler_status(
555566

556567
if scheduler is None:
557568
return SchedulerStatus(
569+
enabled=False,
570+
interval_minutes=_scheduler_interval,
558571
status="error",
559572
jobs=[],
560573
uptime=None
@@ -575,12 +588,16 @@ async def get_scheduler_status(
575588
logger.warning(f"Failed to get job info: {e}")
576589

577590
return SchedulerStatus(
591+
enabled=True,
592+
interval_minutes=_scheduler_interval,
578593
status="running",
579594
jobs=jobs_info,
580595
uptime="Running"
581596
)
582597
else:
583598
return SchedulerStatus(
599+
enabled=False,
600+
interval_minutes=_scheduler_interval,
584601
status="stopped",
585602
jobs=[],
586603
uptime=None
@@ -589,6 +606,8 @@ async def get_scheduler_status(
589606
except Exception as e:
590607
logger.error(f"Failed to get scheduler status: {e}")
591608
return SchedulerStatus(
609+
enabled=False,
610+
interval_minutes=_scheduler_interval,
592611
status="error",
593612
jobs=[],
594613
uptime=None
@@ -598,11 +617,13 @@ async def get_scheduler_status(
598617
@router.post("/scheduler/start")
599618
@require_permission(Permission.SYSTEM_MAINTENANCE)
600619
async def start_scheduler(
620+
request: SchedulerStartRequest,
601621
current_user: dict = Depends(get_current_user)
602622
):
603623
"""Start the monitoring scheduler"""
604624
try:
605-
global _scheduler
625+
global _scheduler, _scheduler_interval
626+
_scheduler_interval = request.interval_minutes
606627
scheduler = get_scheduler()
607628

608629
if scheduler is None:
@@ -618,11 +639,31 @@ async def start_scheduler(
618639

619640
if not scheduler.running:
620641
scheduler.start()
621-
logger.info(f"Host monitoring scheduler started by user {current_user.get('username', 'unknown')}")
642+
643+
# Configure the monitoring job with the requested interval
644+
from ..tasks.monitoring_tasks import periodic_host_monitoring
645+
646+
# Remove any existing job first
647+
for job in scheduler.get_jobs():
648+
if job.id == "host_monitoring":
649+
scheduler.remove_job(job.id)
650+
651+
# Add the job with the specified interval
652+
scheduler.add_job(
653+
periodic_host_monitoring,
654+
'interval',
655+
minutes=_scheduler_interval,
656+
id='host_monitoring',
657+
name='Host Monitoring Task',
658+
replace_existing=True
659+
)
660+
661+
logger.info(f"Host monitoring scheduler started with {_scheduler_interval} minute interval by user {current_user.get('username', 'unknown')}")
622662

623663
return {
624664
"message": "Scheduler started successfully",
625-
"status": "running"
665+
"status": "running",
666+
"interval_minutes": _scheduler_interval
626667
}
627668
else:
628669
return {
@@ -675,6 +716,53 @@ async def stop_scheduler(
675716
)
676717

677718

719+
@router.put("/scheduler")
720+
@require_permission(Permission.SYSTEM_MAINTENANCE)
721+
async def update_scheduler(
722+
request: SchedulerUpdateRequest,
723+
current_user: dict = Depends(get_current_user)
724+
):
725+
"""Update scheduler settings"""
726+
try:
727+
global _scheduler_interval
728+
_scheduler_interval = request.interval_minutes
729+
730+
scheduler = get_scheduler()
731+
732+
# If scheduler is running, we need to reschedule the job with the new interval
733+
if scheduler and scheduler.running:
734+
# Remove existing jobs
735+
for job in scheduler.get_jobs():
736+
if job.id == "host_monitoring":
737+
scheduler.remove_job(job.id)
738+
739+
# Add new job with updated interval
740+
from ..tasks.monitoring_tasks import periodic_host_monitoring
741+
scheduler.add_job(
742+
periodic_host_monitoring,
743+
'interval',
744+
minutes=_scheduler_interval,
745+
id='host_monitoring',
746+
name='Host Monitoring Task',
747+
replace_existing=True
748+
)
749+
750+
logger.info(f"Scheduler interval updated to {_scheduler_interval} minutes by user {current_user.get('username', 'unknown')}")
751+
752+
return {
753+
"message": f"Scheduler interval updated to {_scheduler_interval} minutes",
754+
"interval_minutes": _scheduler_interval,
755+
"status": "running" if scheduler and scheduler.running else "stopped"
756+
}
757+
758+
except Exception as e:
759+
logger.error(f"Failed to update scheduler: {e}")
760+
raise HTTPException(
761+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
762+
detail=f"Failed to update scheduler: {str(e)}"
763+
)
764+
765+
678766
async def restore_scheduler_state():
679767
"""Restore scheduler state from database on startup"""
680768
try:

0 commit comments

Comments
 (0)