o 1iI@sdZddlZddlZddlZddlmZmZmZddlmZddl m Z ddl m Z ddl mZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlm Z GdddZ!ddZ"e#dkrze"dSdS)z Automation Daemon - Unified daemon for multiple automation modules Manages scheduling and execution for Scheduler, Backup, and future modules N)OptionalDictAny)datetime)BackgroundScheduler) CronTrigger)IntervalTrigger) DateTrigger)logger)Database)SchedulerConfig) setup_logging)convert_unix_to_iso_dayofweek) JobExecutor)NotificationManager)DependencyManagerc@seZdZdZddZddZddZdd Zd d Zd d Z de fddZ de de fddZ defddZdefddZdedefddZdedefdd Zd!d"Zdefd#d$Zdefd%d&Zded'eefd(d)Zded'ee effd*d+Zded'ee effd,d-Zd'e fd.d/Zd0S)1AutomationDaemonz3Unified daemon managing multiple automation modulescCstdtdt|_t|jj|_t|j|j|_ t |j|j|j |_ t |j|j |_ i|_|tdddddd|_d |_ttj|jttj|jtd dS) NdaemonzInitializing Automation Daemonz Europe/RomeTi,)ZcoalesceZ max_instancesZmisfire_grace_time)timezoneZ job_defaultsFzAutomation Daemon initialized)r r infor configr database_pathdbrZnotification_managerrexecutorrdependency_managermodules _load_modulesr schedulerrunningsignalSIGINT_signal_handlerSIGTERM)selfr%/c:\PYTHON\Scheduler\daemon\automation_daemon.py__init__s(  zAutomationDaemon.__init__c Cstdd|j|jd|jd<tdzddlm}d||jd |jd <td WntyG}zt d |WYd }~nd }~wwzddl m }d||jd |jd<tdWntyz}zt d|WYd }~nd }~wwtdt |jdd S)z&Load and initialize automation moduleszLoading automation modules...Z Scheduler)namerrru ✓ Scheduler module loadedr) BackupModuleZBackup)r(instancebackupu ✓ Backup module loadedu# ✗ Backup module not available: N) SyncModuleZSyncsyncu ✓ Sync module loadedu! ✗ Sync module not available: Loaded z module(s)) r rrrrZmodules.backupr)r ExceptionwarningZ modules.syncr,len)r$r)er,r%r%r&rFs6       zAutomationDaemon._load_modulescCstd|d|dS)zHandle shutdown signalszReceived signal z, shutting down...N)r rshutdown)r$signumframer%r%r&r"qs z AutomationDaemon._signal_handlerc CstdzczF||jd|_tdtdt|jdz|jr;t |j dd| |js*Wnt yJtdYnwWntya}z td |d }~wwW|d S|w) zStart the automation daemonzStarting Automation DaemonTz&Automation Daemon started successfullyr.z schedule(s)zdaemon.check_interval_secondszKeyboard interrupt receivedzError starting daemon: N)r r_load_schedulesrstartrr1get_jobstimesleeprget _health_checkKeyboardInterruptr/ exceptionr3)r$r2r%r%r&r8vs0    zAutomationDaemon.startc CsT|jsdStdd|_|jjr|jjddtd|j}|r_tdt|dd }t}|rSt||krSt d |j}|rSt||ks?|r_t t|d |j D]>\}}d |vrt |d d rz|d td|dWqdty}ztd|d|WYd}~qdd}~wwqdtddS)zShutdown the daemon gracefullyNzShutting down Automation DaemonFT)waitzAPScheduler stoppedz Waiting for z active jobs to complete...<rz! jobs still running after timeoutr*cleanupzModule 'z' cleanup completedzError cleaning up module '': zAutomation Daemon stopped)rr rrr3rget_active_executionsr1r:r;r0ritemshasattrrBr/error)r$activetimeoutr8 module_name module_datar2r%r%r&r3s:      "zAutomationDaemon.shutdownc Cs~|jjdd}tdt|d|D](}z||Wqty<}ztd|dd|WYd}~qd}~wwdS) z:Load all enabled schedules from database and schedule themT) enabled_onlyzLoading z enabled schedule(s)zError scheduling 'r(rCN)rget_all_schedulesr rr1_schedule_itemr/rG)r$Z schedulesscheduler2r%r%r&r7s&z AutomationDaemon._load_schedulesrOc Csddl}|d}|d}|d}|d}|d}z ||d}Wn|d}Y|d kr9td |d dS|||} | sLtd |d dS|dkrW|j} |g} nI|dkrb|j} |g} n>|dkrzd|jvrrt ddS|j } ||g} n&|dkrd|jvrt ddS|j } ||g} nt d|d|d dS|j j | | | d||ddtd|d|d|d|d| dS) zz Schedule an item with APScheduler Args: schedule: Schedule definition from database rNidr( target_type target_id schedule_typeschedule_configmanualzSkipping manual schedule ''z&Could not build trigger for schedule 'z ', skippingjobgroupbackup_profiler+z0Cannot schedule backup: backup module not loaded sync_profiler-z,Cannot schedule sync: sync module not loadedzUnknown target_type 'z' in schedule ' schedule_T)functriggerargsrPr(Zreplace_existingz Scheduled 'z' (ID z):  z with )jsonloadsr debug_build_triggerr0_execute_scheduled_job_execute_scheduled_grouprrG_execute_scheduled_backup_execute_scheduled_syncrZadd_jobr) r$rOr` schedule_idZ schedule_namerQrRrSrTr] exec_funcZ exec_argsr%r%r&rNs\        , zAutomationDaemon._schedule_itemrSrTcCsf|dkr|d}|rt|}t|SdS|dkr!tdi|S|dkr1|d}|r1t|dSdS)z Build APScheduler trigger from schedule configuration Args: schedule_type: 'cron', 'interval', or 'date' schedule_config: Configuration dict Returns: APScheduler trigger object cronintervaldaterun_date)rmNr%)r<rrZ from_crontabrr )r$rSrTZ cron_exprZ cron_expr_isormr%r%r&rcs     zAutomationDaemon._build_triggerjob_idc Cstd|z%|jj|dd}|r"td|d|dWd Std|dWd StyK}ztd|d |WYd }~d Sd }~ww) zv Execute a scheduled job (called by APScheduler) Args: job_id: Job ID to execute z(Triggered scheduled execution of job ID r triggered_byzJob ID z$ queued for execution (execution ID )z could not be queuedzError executing scheduled job : N)r rr execute_jobr0r/r?)r$rn execution_idr2r%r%r&rd/s$z'AutomationDaemon._execute_scheduled_jobgroup_idc Cstd|z0|jj|dd}|dr"td|dWd St|dg}td|d|d Wd StyV}ztd |d |WYd }~d Sd }~ww) z| Execute a scheduled group (called by APScheduler) Args: group_id: Group ID to execute z*Triggered scheduled execution of group ID rrosuccessz Group ID  completed successfully failed_jobsz completed with z failed job(s)z Error executing scheduled group rrN) r rrexecute_job_groupr<r1r0r/r?)r$ruresultZ failed_countr2r%r%r&reCs $z)AutomationDaemon._execute_scheduled_grouprh profile_idc Ctd|z2|jdd}|||}|dr'td|dWd S|dd}td|d |Wd StyX}ztd |d |WYd }~d Sd }~ww) z Execute a scheduled backup (called by APScheduler) Args: schedule_id: Schedule ID that triggered profile_id: Backup profile ID to execute z3Triggered scheduled execution of backup profile ID r+r*rvzBackup profile ID rwrG Unknown error failed: z!Error executing scheduled backup rrNr rrZ schedule_itemr<rGr/r?)r$rhr{ backup_modulerzrGr2r%r%r&rf\   $z*AutomationDaemon._execute_scheduled_backupc Cr|) z Execute a scheduled sync (called by APScheduler) Args: schedule_id: Schedule ID that triggered profile_id: Sync profile ID to execute z1Triggered scheduled execution of sync profile ID r-r*rvzSync profile ID rwrGr}r~zError executing scheduled sync rrNr)r$rhr{ sync_modulerzrGr2r%r%r&rgsrz(AutomationDaemon._execute_scheduled_synccCs|j}|D]<}t|d}t|}|j|d}|rC||ddkrCtd|dd|jj |ddtd d qd S) z!Periodic health check and cleanup start_timerntimeout_secondsz Execution rPz! appears stuck, marking as failedfailedz@Execution exceeded 2x timeout - marked as failed by health check)statusend_time error_messageN) rrDr fromisoformatnow total_secondsget_jobr r0update_execution)r$rH executionrZ running_timerWr%r%r&r=s zAutomationDaemon._health_checkcCsD|j|}|r|dr ||td|dddSdSdS)z} Add or update a schedule in the scheduler Args: schedule_id: Schedule ID to add/update enabledzAdded/updated schedule 'r(z' in schedulerN)r get_schedulerNr r)r$rhrOr%r%r& add_schedules   zAutomationDaemon.add_schedulec Cshz|jd|td|dWdSty3}ztd|d|WYd}~dSd}~ww)zt Remove a schedule from the scheduler Args: schedule_id: Schedule ID to remove r[zRemoved schedule ID z from schedulerzCould not remove schedule z from scheduler: N)rZ remove_jobr rr/r0)r$rhr2r%r%r&remove_schedules$z AutomationDaemon.remove_schedulereturncCs td||jj|ddS)z Execute a job manually (outside of schedule) Args: job_id: Job ID to execute Returns: Execution ID z&Manual execution requested for job ID rUro)r rrrs)r$rnr%r%r&execute_job_manuallys z%AutomationDaemon.execute_job_manuallycCJtd|d|jvrd}t|d|dS|jdd}||S)z Execute a backup manually (outside of schedule) Args: profile_id: Backup profile ID to execute Returns: Result dict with success status and details z1Manual execution requested for backup profile ID r+zBackup module not loadedFrvrGr*)r rrrGZexecute_backup)r$r{ error_msgrr%r%r&execute_backup_manually    z(AutomationDaemon.execute_backup_manuallycCr)z Execute a sync manually (outside of schedule) Args: profile_id: Sync profile ID to execute Returns: Result dict with success status and details z/Manual execution requested for sync profile ID r-zSync module not loadedFrr*)r rrrGZ execute_sync)r$r{rrr%r%r&execute_sync_manuallyrz&AutomationDaemon.execute_sync_manuallycCsr|j}|j}i}|jD]\}}d|d|d||<q|jt|t|||r5t |dj dSddS)zGet daemon status informationTr()Zloadedr(rN)rZscheduled_jobsactive_executionsr next_run_time) rr9rrDrrEr<rr1strr)r$jobsrZmodules_statusrJrKr%r%r&get_daemon_statuss    z"AutomationDaemon.get_daemon_statusN)__name__ __module__ __qualname____doc__r'rr"r8r3r7dictrNrrcintrdrerfrgr=rrrrrrrrrr%r%r%r&rs*)+!& H   rc Cstdtdtdt}z|Wn,ty&tdYntyD}ztd|tdWYd}~nd}~wwtddS)zMain entry point for daemonz<============================================================z#Python Automation Daemon - StartingzReceived KeyboardInterruptzFatal error in daemon: rNr) r rrr8r>r/r?sysexit)rr2r%r%r&mains     r__main__)$rr:r rtypingrrrrZ!apscheduler.schedulers.backgroundrZapscheduler.triggers.cronrZapscheduler.triggers.intervalrZapscheduler.triggers.dater logurur core.databaser core.configr core.loggerr Zcore.cron_utilsrdaemon.job_executorrZdaemon.notification_managerrdaemon.dependency_managerrrrrr%r%r%r&s4             l