You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

149 regels
4.0 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # License: MIT. See LICENSE
  3. """
  4. Events:
  5. always
  6. daily
  7. monthly
  8. weekly
  9. """
  10. # imports - standard imports
  11. import os
  12. import time
  13. # imports - third party imports
  14. import schedule
  15. # imports - module imports
  16. import frappe
  17. from frappe.installer import update_site_config
  18. from frappe.utils import get_sites, now_datetime
  19. from frappe.utils.background_jobs import get_jobs
  20. DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
  21. def start_scheduler():
  22. '''Run enqueue_events_for_all_sites every 2 minutes (default).
  23. Specify scheduler_interval in seconds in common_site_config.json'''
  24. schedule.every(frappe.get_conf().scheduler_tick_interval or 60).seconds.do(enqueue_events_for_all_sites)
  25. while True:
  26. schedule.run_pending()
  27. time.sleep(1)
  28. def enqueue_events_for_all_sites():
  29. '''Loop through sites and enqueue events that are not already queued'''
  30. if os.path.exists(os.path.join('.', '.restarting')):
  31. # Don't add task to queue if webserver is in restart mode
  32. return
  33. with frappe.init_site():
  34. sites = get_sites()
  35. for site in sites:
  36. try:
  37. enqueue_events_for_site(site=site)
  38. except Exception as e:
  39. print(e.__class__, 'Failed to enqueue events for site: {}'.format(site))
  40. def enqueue_events_for_site(site):
  41. def log_and_raise():
  42. error_message = 'Exception in Enqueue Events for Site {0}\n{1}'.format(site, frappe.get_traceback())
  43. frappe.logger("scheduler").error(error_message)
  44. try:
  45. frappe.init(site=site)
  46. frappe.connect()
  47. if is_scheduler_inactive():
  48. return
  49. enqueue_events(site=site)
  50. frappe.logger("scheduler").debug('Queued events for site {0}'.format(site))
  51. except frappe.db.OperationalError as e:
  52. if frappe.db.is_access_denied(e):
  53. frappe.logger("scheduler").debug('Access denied for site {0}'.format(site))
  54. else:
  55. log_and_raise()
  56. except:
  57. log_and_raise()
  58. finally:
  59. frappe.destroy()
  60. def enqueue_events(site):
  61. if schedule_jobs_based_on_activity():
  62. frappe.flags.enqueued_jobs = []
  63. queued_jobs = get_jobs(site=site, key='job_type').get(site) or []
  64. for job_type in frappe.get_all('Scheduled Job Type', ('name', 'method'), dict(stopped=0)):
  65. if not job_type.method in queued_jobs:
  66. # don't add it to queue if still pending
  67. frappe.get_doc('Scheduled Job Type', job_type.name).enqueue()
  68. def is_scheduler_inactive():
  69. if frappe.local.conf.maintenance_mode:
  70. return True
  71. if frappe.local.conf.pause_scheduler:
  72. return True
  73. if is_scheduler_disabled():
  74. return True
  75. return False
  76. def is_scheduler_disabled():
  77. if frappe.conf.disable_scheduler:
  78. return True
  79. return not frappe.utils.cint(frappe.db.get_single_value("System Settings", "enable_scheduler"))
  80. def toggle_scheduler(enable):
  81. frappe.db.set_value("System Settings", None, "enable_scheduler", 1 if enable else 0)
  82. def enable_scheduler():
  83. toggle_scheduler(True)
  84. def disable_scheduler():
  85. toggle_scheduler(False)
  86. def schedule_jobs_based_on_activity(check_time=None):
  87. '''Returns True for active sites defined by Activity Log
  88. Returns True for inactive sites once in 24 hours'''
  89. if is_dormant(check_time=check_time):
  90. # ensure last job is one day old
  91. last_job_timestamp = frappe.db.get_last_created('Scheduled Job Log')
  92. if not last_job_timestamp:
  93. return True
  94. else:
  95. if ((check_time or now_datetime()) - last_job_timestamp).total_seconds() >= 86400:
  96. # one day is passed since jobs are run, so lets do this
  97. return True
  98. else:
  99. # schedulers run in the last 24 hours, do nothing
  100. return False
  101. else:
  102. # site active, lets run the jobs
  103. return True
  104. def is_dormant(check_time=None):
  105. last_activity_log_timestamp = frappe.db.get_last_created('Activity Log')
  106. since = (frappe.get_system_settings('dormant_days') or 4) * 86400
  107. if not last_activity_log_timestamp:
  108. return True
  109. if ((check_time or now_datetime()) - last_activity_log_timestamp).total_seconds() >= since:
  110. return True
  111. return False
  112. @frappe.whitelist()
  113. def activate_scheduler():
  114. if is_scheduler_disabled():
  115. enable_scheduler()
  116. if frappe.conf.pause_scheduler:
  117. update_site_config('pause_scheduler', 0)