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.
 
 
 
 
 
 

97 lines
2.7 KiB

  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe
  5. from frappe.utils.scheduler import enqueue_events
  6. from frappe.celery_app import get_celery, celery_task, task_logger, LONGJOBS_PREFIX
  7. from frappe.cli import get_sites
  8. from frappe.utils.file_lock import delete_lock
  9. @celery_task()
  10. def sync_queues():
  11. """notifies workers to monitor newly added sites"""
  12. app = get_celery()
  13. shortjob_workers, longjob_workers = get_workers(app)
  14. if shortjob_workers:
  15. for worker in shortjob_workers:
  16. sync_worker(app, worker)
  17. if longjob_workers:
  18. for worker in longjob_workers:
  19. sync_worker(app, worker, prefix=LONGJOBS_PREFIX)
  20. def get_workers(app):
  21. longjob_workers = []
  22. shortjob_workers = []
  23. active_queues = app.control.inspect().active_queues()
  24. for worker in active_queues:
  25. if worker.startswith(LONGJOBS_PREFIX):
  26. longjob_workers.append(worker)
  27. else:
  28. shortjob_workers.append(worker)
  29. return shortjob_workers, longjob_workers
  30. def sync_worker(app, worker, prefix=''):
  31. active_queues = set(get_active_queues(app, worker))
  32. required_queues = set(get_required_queues(app, prefix=prefix))
  33. to_add = required_queues - active_queues
  34. to_remove = active_queues - required_queues
  35. for queue in to_add:
  36. app.control.broadcast('add_consumer', arguments={
  37. 'queue': queue
  38. }, reply=True, destination=[worker])
  39. for queue in to_remove:
  40. app.control.broadcast('cancel_consumer', arguments={
  41. 'queue': queue
  42. }, reply=True, destination=[worker])
  43. def get_active_queues(app, worker):
  44. active_queues = app.control.inspect().active_queues()
  45. return [queue['name'] for queue in active_queues[worker]]
  46. def get_required_queues(app, prefix=''):
  47. ret = []
  48. for site in get_sites():
  49. ret.append('{}{}'.format(prefix, site))
  50. ret.append(app.conf['CELERY_DEFAULT_QUEUE'])
  51. return ret
  52. @celery_task()
  53. def scheduler_task(site, event, handler, now=False):
  54. from frappe.utils.scheduler import log
  55. traceback = ""
  56. task_logger.info('running {handler} for {site} for event: {event}'.format(handler=handler, site=site, event=event))
  57. try:
  58. if not now:
  59. frappe.connect(site=site)
  60. frappe.get_attr(handler)()
  61. except Exception:
  62. frappe.db.rollback()
  63. traceback = log(handler, "Method: {event}, Handler: {handler}".format(event=event, handler=handler))
  64. task_logger.warn(traceback)
  65. raise
  66. else:
  67. frappe.db.commit()
  68. finally:
  69. delete_lock(handler)
  70. if not now:
  71. frappe.destroy()
  72. task_logger.info('ran {handler} for {site} for event: {event}'.format(handler=handler, site=site, event=event))
  73. @celery_task()
  74. def enqueue_scheduler_events():
  75. for site in get_sites():
  76. frappe.connect(site=site)
  77. enqueue_events(site)
  78. frappe.destroy()