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.
149 lines
4 KiB
Python
Executable file
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)
|