Loading...
Loading...
Implementation workflows for Frappe scheduled tasks and background jobs (v14/v15/v16). Covers hooks.py scheduler_events, frappe.enqueue, queue selection, job deduplication, and error handling. Triggers: how to schedule task, background job, cron job, async processing, queue selection, job deduplication, scheduler implementation.
npx skill4agent add openaec-foundation/erpnext_anthropic_claude_development_skill_package erpnext-impl-schedulererpnext-syntax-scheduler┌─────────────────────────────────────────────────────────────────────┐
│ SCHEDULER DECISION │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Run at fixed intervals or times? │
│ ├── YES → Scheduler Event (hooks.py) │
│ │ See: references/workflows.md §1-2 │
│ │ │
│ └── NO → Run in response to user action? │
│ ├── YES → frappe.enqueue() │
│ │ See: references/workflows.md §3-4 │
│ │ │
│ └── NO → Probably neither - reconsider requirements │
│ │
└─────────────────────────────────────────────────────────────────────┘| Aspect | Scheduler Event | frappe.enqueue |
|---|---|---|
| Triggered by | Time/interval | Code execution |
| Defined in | hooks.py | Python code |
| Arguments | None (must be parameterless) | Any serializable data |
| Use case | Daily cleanup, hourly sync | User-triggered long task |
| Restart behavior | Runs on schedule | Lost if worker restarts |
┌─────────────────────────────────────────────────────────────────────┐
│ SCHEDULER EVENT TYPE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Simple recurring interval? │
│ ├── Every minute → scheduler_events.cron["* * * * *"] │
│ ├── Hourly → scheduler_events.hourly │
│ ├── Daily → scheduler_events.daily │
│ ├── Weekly → scheduler_events.weekly │
│ └── Monthly → scheduler_events.monthly │
│ │
│ Complex schedule (e.g., "weekdays at 9am")? │
│ └── scheduler_events.cron["0 9 * * 1-5"] │
│ │
│ Run after every request? │
│ └── scheduler_events.all (use sparingly!) │
│ │
└─────────────────────────────────────────────────────────────────────┘| Queue | Timeout | Use For |
|---|---|---|
| 5 min | Quick operations (<1 min) |
| 5 min | Standard tasks (1-3 min) |
| 30 min | Heavy processing (>3 min) |
short# myapp/tasks.py
import frappe
def daily_cleanup():
"""Daily cleanup task - no parameters allowed"""
frappe.db.delete("Error Log", {"creation": ("<", frappe.utils.add_days(None, -30))})
frappe.db.commit()# hooks.py
scheduler_events = {
"daily": [
"myapp.tasks.daily_cleanup"
]
}bench migrate# myapp/api.py
import frappe
from frappe import enqueue
@frappe.whitelist()
def process_documents(doctype, filters):
enqueue(
"myapp.tasks.process_batch",
queue="long",
timeout=1800,
job_id=f"process_{doctype}_{frappe.session.user}", # v15+ dedup
doctype=doctype,
filters=filters
)
return {"status": "queued"}# ❌ WRONG
def my_task(doctype): # Arguments not supported
pass
# ✅ CORRECT
def my_task(): # Parameterless
doctype = "Sales Invoice" # Hardcode or read from settingsbench migrate # Required to register new scheduler events# ❌ WRONG - Slow
for doc in docs:
doc.save()
frappe.db.commit() # Commit per record
# ✅ CORRECT - Fast
for doc in docs:
doc.save()
frappe.db.commit() # Single commit after batchenqueue(..., job_id="unique_identifier") # Prevents duplicate jobs| Aspect | v14 | v15 | v16 |
|---|---|---|---|
| Tick interval | 4 min | 60 sec | 60 sec |
| Job dedup | | | |
| Cron support | ✅ | ✅ | ✅ |
# v14
enqueue(..., job_name="unique_id")
# v15+
enqueue(..., job_id="unique_id")| File | Contents |
|---|---|
| workflows.md | Step-by-step implementation patterns |
| decision-tree.md | Detailed decision flowcharts |
| examples.md | Complete working examples |
| anti-patterns.md | Common mistakes to avoid |
erpnext-syntax-schedulererpnext-errors-serverscripts