seitime-frappe/frappe/utils/scheduler.py
Gavin D'souza 3446026555 chore: Update header: license.txt => LICENSE
The license.txt file has been replaced with LICENSE for quite a while
now. INAL but it didn't seem accurate to say "hey, checkout license.txt
although there's no such file". Apart from this, there were
inconsistencies in the headers altogether...this change brings
consistency.
2021-09-03 12:02:59 +05:30

149 lines
4 KiB
Python
Executable file

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
"""
Events:
always
daily
monthly
weekly
"""
# imports - standard imports
import os
import time
# imports - third party imports
import schedule
# imports - module imports
import frappe
from frappe.core.doctype.user.user import STANDARD_USERS
from frappe.installer import update_site_config
from frappe.utils import get_sites, now_datetime
from frappe.utils.background_jobs import get_jobs
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
def start_scheduler():
'''Run enqueue_events_for_all_sites every 2 minutes (default).
Specify scheduler_interval in seconds in common_site_config.json'''
schedule.every(frappe.get_conf().scheduler_tick_interval or 60).seconds.do(enqueue_events_for_all_sites)
while True:
schedule.run_pending()
time.sleep(1)
def enqueue_events_for_all_sites():
'''Loop through sites and enqueue events that are not already queued'''
if os.path.exists(os.path.join('.', '.restarting')):
# Don't add task to queue if webserver is in restart mode
return
with frappe.init_site():
sites = get_sites()
for site in sites:
try:
enqueue_events_for_site(site=site)
except Exception as e:
print(e.__class__, 'Failed to enqueue events for site: {}'.format(site))
def enqueue_events_for_site(site):
def log_and_raise():
error_message = 'Exception in Enqueue Events for Site {0}\n{1}'.format(site, frappe.get_traceback())
frappe.logger("scheduler").error(error_message)
try:
frappe.init(site=site)
frappe.connect()
if is_scheduler_inactive():
return
enqueue_events(site=site)
frappe.logger("scheduler").debug('Queued events for site {0}'.format(site))
except frappe.db.OperationalError as e:
if frappe.db.is_access_denied(e):
frappe.logger("scheduler").debug('Access denied for site {0}'.format(site))
else:
log_and_raise()
except:
log_and_raise()
finally:
frappe.destroy()
def enqueue_events(site):
if schedule_jobs_based_on_activity():
frappe.flags.enqueued_jobs = []
queued_jobs = get_jobs(site=site, key='job_type').get(site) or []
for job_type in frappe.get_all('Scheduled Job Type', ('name', 'method'), dict(stopped=0)):
if not job_type.method in queued_jobs:
# don't add it to queue if still pending
frappe.get_doc('Scheduled Job Type', job_type.name).enqueue()
def is_scheduler_inactive():
if frappe.local.conf.maintenance_mode:
return True
if frappe.local.conf.pause_scheduler:
return True
if is_scheduler_disabled():
return True
return False
def is_scheduler_disabled():
if frappe.conf.disable_scheduler:
return True
return not frappe.utils.cint(frappe.db.get_single_value("System Settings", "enable_scheduler"))
def toggle_scheduler(enable):
frappe.db.set_value("System Settings", None, "enable_scheduler", 1 if enable else 0)
def enable_scheduler():
toggle_scheduler(True)
def disable_scheduler():
toggle_scheduler(False)
def schedule_jobs_based_on_activity(check_time=None):
'''Returns True for active sites defined by Activity Log
Returns True for inactive sites once in 24 hours'''
if is_dormant(check_time=check_time):
# ensure last job is one day old
last_job_timestamp = frappe.db.get_last_created('Scheduled Job Log')
if not last_job_timestamp:
return True
else:
if ((check_time or now_datetime()) - last_job_timestamp).total_seconds() >= 86400:
# one day is passed since jobs are run, so lets do this
return True
else:
# schedulers run in the last 24 hours, do nothing
return False
else:
# site active, lets run the jobs
return True
def is_dormant(check_time=None):
last_activity_log_timestamp = frappe.db.get_last_created('Activity Log')
since = (frappe.get_system_settings('dormant_days') or 4) * 86400
if not last_activity_log_timestamp:
return True
if ((check_time or now_datetime()) - last_activity_log_timestamp).total_seconds() >= since:
return True
return False
@frappe.whitelist()
def activate_scheduler():
if is_scheduler_disabled():
enable_scheduler()
if frappe.conf.pause_scheduler:
update_site_config('pause_scheduler', 0)