* - trigger new "cron" event - check cron string syntax - added croniter to requirements * - run scheduler ever 60 sec - trigger all enabled events - enqueue if now >= next time execution since last one * Update task-runner.md * fixed tests * fix triggering with now = True * modified sobstitution to cron_map modified annually label to annual * ability to use labels defined in cron_map in cron string definition
94 lines
2.8 KiB
Markdown
Executable file
94 lines
2.8 KiB
Markdown
Executable file
# Scheduled Tasks
|
|
|
|
Finally, an application also has to send email notifications and do other kind of scheduled tasks. In Frappé, if you have setup the bench, the task / scheduler is setup via RQ using Redis Queue.
|
|
|
|
To add a new task handler, go to `hooks.py` and add a new handler. Default handlers are `all`, `daily`, `weekly`, `monthly`, `cron`. The `all` handler is called every 4 minutes by default.
|
|
|
|
# Scheduled Tasks
|
|
# ---------------
|
|
|
|
scheduler_events = {
|
|
"daily": [
|
|
"library_management.tasks.daily"
|
|
],
|
|
"cron": {
|
|
"0/10 * * * *": [
|
|
"library_management.task.run_every_ten_mins"
|
|
],
|
|
"15 18 * * *": [
|
|
"library_management.task.every_day_at_18_15"
|
|
]
|
|
}
|
|
|
|
}
|
|
|
|
Here we can point to a Python function and that function will be executed every day. Let us look what this function looks like:
|
|
|
|
# Copyright (c) 2013, Frappé
|
|
# For license information, please see license.txt
|
|
|
|
from __future__ import unicode_literals
|
|
import frappe
|
|
from frappe.utils import datediff, nowdate, format_date, add_days
|
|
|
|
def every_ten_minutes():
|
|
# stuff to do every 10 minutes
|
|
pass
|
|
|
|
def every_day_at_18_15():
|
|
# stuff to do every day at 6:15pm
|
|
pass
|
|
|
|
def daily():
|
|
loan_period = frappe.db.get_value("Library Management Settings",
|
|
None, "loan_period")
|
|
|
|
overdue = get_overdue(loan_period)
|
|
|
|
for member, items in overdue.iteritems():
|
|
content = """<h2>Following Items are Overdue</h2>
|
|
<p>Please return them as soon as possible</p><ol>"""
|
|
|
|
for i in items:
|
|
content += "<li>{0} ({1}) due on {2}</li>".format(i.article_name,
|
|
i.article,
|
|
format_date(add_days(i.transaction_date, loan_period)))
|
|
|
|
content += "</ol>"
|
|
|
|
recipient = frappe.db.get_value("Library Member", member, "email_id")
|
|
frappe.sendmail(recipients=[recipient],
|
|
sender="test@example.com",
|
|
subject="Library Articles Overdue", content=content, bulk=True)
|
|
|
|
def get_overdue(loan_period):
|
|
# check for overdue articles
|
|
today = nowdate()
|
|
|
|
overdue_by_member = {}
|
|
articles_transacted = []
|
|
|
|
for d in frappe.db.sql("""select name, article, article_name,
|
|
library_member, member_name
|
|
from `tabLibrary Transaction`
|
|
order by transaction_date desc, modified desc""", as_dict=1):
|
|
|
|
if d.article in articles_transacted:
|
|
continue
|
|
|
|
if d.transaction_type=="Issue" and \
|
|
datediff(today, d.transaction_date) > loan_period:
|
|
overdue_by_member.setdefault(d.library_member, [])
|
|
overdue_by_member[d.library_member].append(d)
|
|
|
|
articles_transacted.append(d.article)
|
|
|
|
We can place the above code in any accessible Python module. The route is defined in `hooks.py`, so for our purposes we would place this code in `library_management/tasks.py`.
|
|
|
|
Note:
|
|
|
|
1. We get the loan period from **Library Management Settings** by using `frappe.db.get_value`.
|
|
1. We run a query in the database with `frappe.db.sql`
|
|
1. Email is sent via `frappe.sendmail`
|
|
|
|
{next}
|