Frappe Framework
Tâches de fond (Background Jobs)
Comment exécuter du code Python en arrière-plan avec frappe.enqueue, configurer files et workers, et planifier des tâches périodiques avec le hook scheduler_events.
À quoi servent les tâches de fond
Frappe embarque un système d’exécution de tâches en arrière-plan, appelées tâches de fond (Background Jobs). Il repose sur le paquet schedule et sur une simple boucle infinie de longue durée.
Mettre une tâche en file d’attente
frappe.enqueue
Vous pouvez placer une méthode Python en file d’attente pour qu’elle s’exécute en arrière-plan avec la méthode frappe.enqueue :
def long_running_job(param1, param2):
# expensive tasks
pass
# directly pass the function
frappe.enqueue(long_running_job, queue='short', param1='A', param2='B')
# or pass the full module path as string
frappe.enqueue('app.module.folder.long_running_job', queue='short', param1='A', param2='B')Voici tous les arguments que enqueue accepte :
frappe.enqueue(
method, # python function or a module path as string
queue="default", # one of short, default, long
timeout=None, # pass timeout manually
is_async=True, # if this is True, method is run in worker
now=False, # if this is True, method is run directly (not in a worker)
job_name=None, # specify a job name
enqueue_after_commit=False, # enqueue the job after the database commit is done at the end of the request
at_front=False, # put the job at the front of the queue
**kwargs, # kwargs are passed to the method as arguments
)| Argument | Valeur par défaut | Rôle |
|---|---|---|
method | — | Fonction Python, ou chemin de module sous forme de chaîne. |
queue | "default" | File d’attente : short, default ou long. |
timeout | None | Délai d’expiration passé manuellement. |
is_async | True | Si True, la méthode s’exécute dans un worker. |
now | False | Si True, la méthode s’exécute immédiatement (pas dans un worker). |
job_name | None | Nom donné à la tâche. |
enqueue_after_commit | False | Met la tâche en file seulement après le commit de la base de données, à la fin de la requête. |
at_front | False | Place la tâche en tête de la file. |
**kwargs | — | Arguments nommés transmis à la méthode. |
frappe.enqueue_doc
Vous pouvez aussi mettre en file une méthode d’un Document avec frappe.enqueue_doc :
frappe.enqueue_doc(
doctype,
name,
"do_something", # name of the controller method
queue="long",
timeout=4000,
param="value"
)Le troisième argument est le nom de la méthode du contrôleur à exécuter ; les arguments suivants (queue, timeout, puis les paramètres nommés) sont transmis comme pour enqueue.
Files d’attente (Queues)
Le framework configure trois files d’attente par défaut : short, default et long. Chacune a un délai d’expiration par défaut :
| File | Délai d’expiration par défaut |
|---|---|
short | 300 secondes |
default | 300 secondes |
long | 1500 secondes |
Vous pouvez aussi passer un délai personnalisé à la méthode enqueue.
Files personnalisées
Vous pouvez ajouter vos propres files en les déclarant dans common_site_config.json :
{
...
"workers": {
"myqueue": {
"timeout": 5000, # queue timeout
"background_workers": 4, # number of workers for this queue
}
}
}Pour chaque file, timeout fixe le délai d’expiration et background_workers le nombre de workers qui la consomment.
Workers
Par défaut, Frappe met en place trois types de workers, un par file. La configuration par défaut est la suivante :
bench worker --queue short
bench worker --queue default
bench worker --queue longEn production, ces trois processus sont répliqués selon le nombre de workers d’arrière-plan configuré, afin d’absorber une charge plus élevée.
À retenir
Associer un worker à une seule file n’est qu’une convention ; rien n’oblige à la suivre.
Consommer plusieurs files
Un worker peut consommer plusieurs files : indiquez leurs noms séparés par des virgules.
Exemple : pour fusionner les workers short et default et n’utiliser que deux types de workers au lieu de la configuration par défaut, modifiez la configuration ainsi :
bench worker --queue short,default
bench worker --queue longÀ retenir
Les exemples ci-dessus sont au format Procfile, mais ils s’appliquent tout aussi facilement à une configuration supervisor ou systemd.
Mode burst avec --burst
bench worker --queue short --burstCette commande lance un worker temporaire qui consomme la file short et s’arrête dès que la file est vide. Si vous avez périodiquement besoin de plus de workers, vous pouvez utiliser le crontab de votre système pour démarrer des workers en mode burst à des heures précises.
Événements planifiés (Scheduler Events)
Les événements planifiés servent à exécuter des tâches périodiques en arrière-plan, grâce au hook scheduler_events.
app/hooks.py
scheduler_events = {
"hourly": [
# will run hourly
"app.scheduled_tasks.update_database_usage"
],
}app/scheduled_tasks.py
def update_database_usage():
passÀ retenir
Après toute modification des événements planifiés dans hooks.py, exécutez bench migrate pour que les changements soient pris en compte.
Événements disponibles
| Événement | Déclenchement |
|---|---|
hourly, daily, weekly, monthly | Toutes les heures, tous les jours, toutes les semaines, tous les mois. |
hourly_long, daily_long, weekly_long, monthly_long | Même fréquence, mais exécutés dans le worker long, adapté aux tâches de longue durée. |
all | Toutes les 4 minutes. L’intervalle se règle avec la clé scheduler_interval de common_site_config.json. |
cron | Une expression cron valide, interprétée par croniter. |
Exemples d’utilisation :
scheduler_events = {
"daily": [
"app.scheduled_tasks.manage_recurring_invoices"
],
"daily_long": [
"app.scheduled_tasks.take_backups_daily"
],
"cron": {
"15 18 * * *": [
"app.scheduled_tasks.delete_all_barcodes_for_users"
],
"*/6 * * * *": [
"app.scheduled_tasks.collect_error_snapshots"
],
"annual": [
"app.scheduled_tasks.collect_error_snapshots"
]
}
}Événements planifiés configurables
Quand l’intervalle de déclenchement doit être réglable par l’utilisateur, créez un enregistrement Scheduler Event, puis une entrée Scheduled Job Type rattachée à cet enregistrement. Cette approche ne nécessite pas le hook scheduler_events.
Exemple :
# Create `Scheduler Event` record
sch_eve = frappe.new_doc("Scheduler Event")
sch_eve.scheduled_against = "Process Payment Reconciliation"
sch_eve.save()
# Create `Scheduled Job Type`
job = frappe.new_doc("Scheduled Job Type")
job.frequency = "Cron"
job.scheduler_event = sch_eve.name
job.cron_format = "0/5 * * * *" # runs every five minutes
job.save()L’intervalle du Scheduled Job Type peut être modifié par la suite, et cette modification survit aux migrations du bench.
Attention
Les tâches déclenchées par le planificateur s’exécutent sous l’utilisateur Administrator. Les documents créés par une tâche planifiée appartiennent donc à Administrator, sauf indication contraire.
