frappe-impl-scheduler について
Frappe 開発者向けに、スケジュールタスクとバックグラウンドジョブの実装手順をまとめたガイドです。スケジューラーイベントと `frappe.enqueue` の使い分けから、テスト、監視、エラー分離、長時間処理の分割まで扱います。
主な機能
- 01イベントとバックグラウンドキューの選択
- 02イベント頻度とキューの設定
- 03ジョブ実行のテストと監視
- 04バッチエラーと長時間処理への対応
- 05バージョン差分と実装例の参照
活用シーン
- 01定期的なクリーンアップや同期の設定
- 02ユーザー起点の長時間処理のキュー投入
- 03スケジュールタスクのテストと失敗記録の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ impertio-studio/ frappe_claude_skill_package --skill frappe-impl-schedulerインストール後、Claude Code で/frappe-impl-schedulerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/anti-patterns.mddecision-tree.mdexamples.mdworkflows.md詳細
Frappe スケジューラーとバックグラウンドジョブ - 実装
スケジュールされたタスクとバックグラウンドジョブを実装するためのワークフローです。正確な構文については、frappe-syntax-schedulerを参照してください。
バージョン:v14/v15/v16 対応
主な判断:scheduler_events と frappe.enqueue
WHAT ARE YOU BUILDING?
|
+-- Runs at fixed intervals/times?
| +-- YES --> scheduler_events (hooks.py)
| | Task receives NO arguments
| | See: Workflow 1-2
| |
| +-- NO --> Triggered by user action or code?
| +-- YES --> frappe.enqueue()
| | Pass any serializable data
| | See: Workflow 3-4
| |
| +-- NO --> Reconsider requirements
| 項目 | scheduler_events | frappe.enqueue |
|---|---|---|
| 起動条件 | 時刻/間隔 | コードの実行 |
| 定義場所 | hooks.py | Python コード |
| 引数 | なし(引数を取らない必要があります) | シリアライズ可能な任意のデータ |
| 用途 | 毎日のクリーンアップ、毎時の同期 | ユーザーが起動する長時間のタスク |
| キューの制御 | イベントのサフィックス(_long) | queue= パラメーター |
| 再起動時の動作 | スケジュールどおりに実行 | ワーカーの再起動時に失われる |
どのスケジューラーイベントタイプを選ぶべきか?
| 必要性 | イベントキー | キュー |
|---|---|---|
| スケジューラーの各ティック | all | short(絶対に60秒を超えない) |
| 毎時(5分未満) | hourly | short |
| 毎時(5~25分) | hourly_long | long |
| 毎日(5分未満) | daily | short |
| 毎日(5~25分) | daily_long | long |
| 毎週(5分未満) | weekly | short |
| 毎週(5~25分) | weekly_long | long |
| 毎月(5分未満) | monthly | short |
| 毎月(5~25分) | monthly_long | long |
| カスタムスケジュール | cron["expr"] | short |
ルール:5分を超えるタスクには、必ず*_longサフィックスを使用してください。
frappe.enqueue ではどのキューを選ぶべきか?
| キュー | デフォルトのタイムアウト | 用途 |
|---|---|---|
short | 300秒(5分) | 短時間の処理(1分未満) |
default | 300秒(5分) | 標準的なタスク(1~5分) |
long | 1500秒(25分) | 負荷の高い処理(5分超) |
ルール:必ずqueue=を明示的に指定してください。デフォルトに頼ってはいけません。
実装ステップ1:スケジューラーイベント
# myapp/tasks.py
import frappe
def daily_cleanup():
"""Daily cleanup - NO parameters allowed."""
cutoff = frappe.utils.add_days(frappe.utils.nowdate(), -30)
frappe.db.delete("Error Log", {"creation": ("<", cutoff)})
frappe.db.commit()
# hooks.py
scheduler_events = {
"daily": ["myapp.tasks.daily_cleanup"]
}
hooks.py の編集後:必ずbench migrateを実行してください。
実装ステップ2:バックグラウンドジョブ(frappe.enqueue)
# myapp/api.py
import frappe
from frappe.utils.background_jobs import is_job_enqueued
@frappe.whitelist()
def process_documents(doctype, filters):
job_id = f"process_{doctype}_{frappe.session.user}"
if is_job_enqueued(job_id):
return {"message": "Already in progress"}
frappe.enqueue(
"myapp.tasks.process_batch",
queue="long",
timeout=1800,
job_id=job_id,
enqueue_after_commit=True,
doctype=doctype,
filters=filters
)
return {"status": "queued"}
スケジュールされたタスクのテスト
方法1:bench execute(直接実行)
# Run the function directly (no queue involved)
bench --site mysite execute myapp.tasks.daily_cleanup
方法2:bench scheduler(スケジューラー全体のテスト)
# Check scheduler status
bench --site mysite scheduler status
# Enable scheduler
bench --site mysite scheduler enable
# Trigger all pending scheduler events NOW
bench --site mysite scheduler trigger
# Run specific event type
bench --site mysite execute frappe.utils.scheduler.trigger --args "['daily']"
方法3:bench console(対話型)
bench --site mysite console
>>> frappe.enqueue("myapp.tasks.my_task", queue="short", now=True)
# now=True executes synchronously for testing
方法4:Scheduled Job Type の確認
1. Go to: Setup > Scheduled Job Type
2. Find: myapp.tasks.daily_cleanup
3. Verify: Frequency correct, Stopped = No
4. Click "Run Now" to trigger manually
監視
Scheduled Job Log(UI)
Setup > Scheduled Job Log
- Shows every scheduler run with status
- Filter by: status (Success/Failed), creation date
- Check execution time to detect slow tasks
RQ Dashboard
# Start RQ monitor (development)
bench --site mysite rq-dashboard
# Opens at http://localhost:9181
# Show background job status
bench --site mysite show-pending-jobs
bench --site mysite show-failed-jobs
プログラムによるヘルスチェック
def scheduler_health_check():
failed = frappe.db.count("Scheduled Job Log", {
"status": "Failed",
"creation": [">=", frappe.utils.add_to_date(None, hours=-1)]
})
if failed > 5:
frappe.sendmail(
recipients=["[email protected]"],
subject="Scheduler Alert: Many failures",
message=f"{failed} scheduler jobs failed in last hour"
)
スケジュールされたタスクでのエラー処理
レコード単位のエラー分離
def sync_all_orders():
orders = get_pending_orders()
success, errors = 0, 0
for order in orders:
try:
sync_to_external(order)
success += 1
except Exception as e:
errors += 1
frappe.db.rollback()
frappe.log_error(
f"Sync failed for {order}: {e}",
"Order Sync Error"
)
frappe.db.commit()
frappe.logger("sync").info(f"{success} ok, {errors} errors")
ルール:レコードごとの処理は必ずtry-exceptで囲んでください。1件の失敗でバッチ全体を停止させてはいけません。
長時間実行ジョブのパターン
自己連鎖パターン(25分超のタスク)
def process_batch(offset=0, batch_size=500, total=None):
if total is None:
total = frappe.db.count("Sales Invoice", {"custom_processed": 0})
records = frappe.get_all("Sales Invoice",
filters={"custom_processed": 0},
pluck="name", limit=batch_size)
if not records:
return # Done
for name in records:
process_single(name)
frappe.db.commit()
remaining = frappe.db.count("Sales Invoice", {"custom_processed": 0})
if remaining > 0:
frappe.enqueue(
"myapp.tasks.process_batch",
queue="long",
offset=offset + batch_size,
batch_size=batch_size,
total=total
)
ルール:25分を超えるタスクは必ず、自己連鎖するバッチに分割してください。
よくある実装パターン
メールダイジェスト(週次サマリー)
# hooks.py
scheduler_events = {
"cron": {
"0 8 * * 1": ["myapp.newsletter.send_weekly_digest"]
}
}
完全な実装については、references/examples.mdの例4を参照してください。
データクリーンアップ(日次メンテナンス)
scheduler_events = {
"daily_long": ["myapp.maintenance.daily_database_maintenance"]
}
バッチ削除のパターンについては、references/examples.mdの例1を参照してください。
レポート生成(ユーザー起動)
frappe.enqueue(
"myapp.tasks.generate_report",
queue="long",
timeout=3600,
job_id=f"report::{frappe.session.user}",
user=frappe.session.user
)
進捗状況の報告については、references/workflows.mdのワークフロー6を参照してください。
重要なルール
- スケジューラータスクは引数を受け取りません - 設定またはハードコードした値を使用してください
- hooks.py の変更後は必ず
bench migrateを実行してください - イベントの登録に必要です - ジョブはAdministratorとして実行されます - 必ず明示的にコミットしてください
- コミットはバッチ単位で行ってください - レコードごとに行ってはいけません(100~500件ごと)
- ユーザー起動のジョブには必ず
job_idを使用してください - 重複を防止します - ドキュメントイベントからは
enqueue_after_commit=Trueを使用してください - データが存在することを保証します - スケジューラーイベントは軽量にしてください - 負荷の高い処理はバックグラウンドに登録してください
バージョンによる違い
| 項目 | v14 | v15 | v16 |
|---|---|---|---|
| ティック間隔 | 240秒 | 60秒 | 60秒 |
| ジョブ重複排除パラメーター | job_name | job_id | job_id |
enqueue_doc() | はい | はい | はい |
| カスタムキュー | いいえ | はい | はい |
参考ファイル
| ファイル | 内容 |
|---|---|
| workflows.md | 手順を追った実装パターン 8 件 |
| decision-tree.md | 詳細な意思決定フローチャート |
| examples.md | 完全に動作するサンプル 5 件 |
| anti-patterns.md | 避けるべきよくある誤り 14 件 |
関連項目
frappe-syntax-scheduler- フックと enqueue の正確な構文リファレンスfrappe-errors-serverscripts- エラー処理のパターンfrappe-impl-hooks- フック設定のパターンfrappe-ops-bench- スケジューラー管理用の Bench コマンドfrappe-ops-performance- バックグラウンドジョブのパフォーマンス調整frappe-testing-unit- スケジュールされたタスクのロジックのテスト
コメント
Markdown 対応