私はDjangoを使ってWebアプリを開発してきましたが、定期的に実行するようにジョブをスケジュールする方法があるかどうかに興味があります。
基本的には、データベースを調べて定期的に計算や更新を行いたいだけですが、これを実行するための資料が見つからないようです。
誰もがこれを設定する方法を知っていますか?
明確にするために:これを行うためにcron
ジョブを設定できることはわかっていますが、Djangoにこの機能を提供する機能があるかどうかは興味があります。私は人々が多くの設定(できれば0)をする必要なしに自分自身でこのアプリをデプロイできるようにしたいです。
前回サイトにリクエストが送信されてからジョブが実行されたかどうかを確認することで、これらのアクションを「遡及的に」実行することを検討しましたが、少しきれいなものを望んでいます。
私が採用した一つの解決策はこれをすることです:
1) カスタム管理コマンド を作成します。
python manage.py my_cool_command
2)必要なときに自分のコマンドを実行するには、cron
(Linuxの場合)またはat
(Windowsの場合)を使用します。
これは、重いAMQPスタックをインストールする必要がない簡単な解決策です。しかし、他の回答で述べたように、Celeryのようなものを使うことにはいい利点があります。特に、Celeryでは、アプリケーションロジックをcrontabファイルに広げなくてもいいのはいいことです。しかし、cronソリューションは、中小規模のアプリケーションや、多くの外部依存関係を必要としないアプリケーションには非常にうまく機能します。
編集:
それ以降のバージョンのWindowsでは、at
コマンドはWindows 8、Server 2012以降では非推奨です。 schtasks.exe
を同じ用途に使用できます。
私たちが構造化アプリだと思うものをオープンソース化しました。上記のBrianの解決策も暗示しています。すべてのフィードバックが大好きです。
https://github.com/tivix/Django-cron
管理コマンドが1つ付属しています。
./manage.py runcrons
それは仕事です。各cronはクラスとしてモデル化されているので(つまりすべてのオブジェクト指向)、各cronは異なる頻度で実行されます。同じcronタイプが並行して実行されないようにします(crons自体が実行頻度より時間がかかる場合)
ありがとうございます。
興味深い新しいプラガブルDjangoアプリ: Django-chronograph
タイマーとして機能するcronエントリを1つ追加するだけで済み、実行するスクリプトに非常に優れたDjango管理インターフェースがあります。
Django Poor Man's Cronを見てください。これは、スパムロボット、検索エンジンのインデックス作成ロボットなどを利用して、ほぼ定期的にスケジュールされたタスクを実行するDjangoアプリです。
RabbitMQとCeleryには、Cronよりも多くの機能とタスク処理機能があります。タスクの失敗が問題ではなく、次の呼び出しで壊れたタスクを処理すると思われる場合は、Cronで十分です。
Celery& AMQP は、壊れたタスクを処理できるようにし、タスクのmax_retries
属性に到達しました。失敗をログに記録したり、max_retries
に達したら管理者にメールを送信するなど、失敗時にタスクを呼び出すこともできます。
また、アプリケーションを拡張する必要がある場合は、CeleryおよびAMQPサーバーを配布できます。
Crianで管理コマンドを実行するというBrian Nealの提案はうまくいきますが、もう少し堅牢なものを探しているなら(まだCeleryほど精巧ではありません)、 Kronos :のようなライブラリを調べます。
# app/cron.py
import kronos
@kronos.register('0 * * * *')
def task():
pass
私は個人的にcronを使用していますが、 Jobs Scheduling の一部 Django-extensions はおもしろそうです。
私はしばらく前にまったく同じ要件を持っていて、 APScheduler ( ユーザーガイド )を使ってそれを解決しました。
ジョブのスケジューリングを非常に簡単にし、リクエストベースのコード実行から独立させます。以下は、コードで使用した簡単な例です。
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
job = None
def tick():
print('One tick!')\
def start_job():
global job
job = scheduler.add_job(tick, 'interval', seconds=3600)
try:
scheduler.start()
except:
pass
これが誰かに役立つことを願っています!
以下をcron.pyファイルの先頭に追加してください。
#!/usr/bin/python
import os, sys
sys.path.append('/path/to/') # the parent directory of the project
sys.path.append('/path/to/project') # these lines only needed if not on path
os.environ['Django_SETTINGS_MODULE'] = 'myproj.settings'
# imports and code below
私はちょうどこのかなり簡単な解決策について考えました:
パラメータを追加することはできますが、URLにパラメータを追加するだけです。
皆さんの考えを教えてください。
[更新]curlの代わりに Django-extensions のrunjobコマンドを使っています。
私のcronはこんな感じです:
@hourly python /path/to/project/manage.py runjobs hourly
...など、毎日、毎月など。特定のジョブを実行するように設定することもできます。
私はそれがもっと管理しやすくてきれいであると思います。 URLをビューにマッピングする必要はありません。職種とcrontabを定義するだけで準備完了です。
Djangoには含まれていませんが、 Airflow はタスク管理に役立つ最近のプロジェクトです(2016年現在)。
エアフローは、データパイプラインを作成および管理するために使用できるワークフロー自動化およびスケジューリングシステムです。 WebベースのUIは、開発者にこれらのパイプラインを管理および表示するためのさまざまなオプションを提供します。
AirflowはPythonで書かれており、Flaskを使って構築されています。
AirflowはAirbnbのMaxime Beaucheminによって作成され、2015年の春にオープンソース化されました。2016年の冬にApache Software Foundationのインキュベーションプログラムに参加しました。 Gitプロジェクトページです といくつかの追加 背景情報 。
コードの一部の後に、私のviews.py :)とまったく同じように書くことができます。
#######################################
import os,sys
sys.path.append('/home/administrator/development/store')
os.environ['Django_SETTINGS_MODULE']='store.settings'
from Django.core.management impor setup_environ
from store import settings
setup_environ(settings)
#######################################
から http://www.cotellese.net/2007/09/27/running-external-scripts-against-Django-models/
Django-qをぜひチェックしてください。それは追加の設定を必要とせず、商業プロジェクトの生産上の問題を処理するために必要なものすべてを持っています。
それは積極的に開発され、Django、Django ORM、mongo、redisと非常によく統合されています。これが私の設定です:
# Django-q
# -------------------------------------------------------------------------
# See: http://Django-q.readthedocs.io/en/latest/configure.html
Q_CLUSTER = {
# Match recommended settings from docs.
'name': 'DjangoORM',
'workers': 4,
'queue_limit': 50,
'bulk': 10,
'orm': 'default',
# Custom Settings
# ---------------
# Limit the amount of successful tasks saved to Django.
'save_limit': 10000,
# See https://github.com/Koed00/Django-q/issues/110.
'catch_up': False,
# Number of seconds a worker can spend on a task before it's terminated.
'timeout': 60 * 5,
# Number of seconds a broker will wait for a cluster to finish a task before presenting it again. This needs to be
# longer than `timeout`, otherwise the same task will be processed multiple times.
'retry': 60 * 6,
# Whether to force all async() calls to be run with sync=True (making them synchronous).
'sync': False,
# Redirect worker exceptions directly to Sentry error reporter.
'error_reporter': {
'sentry': RAVEN_CONFIG,
},
}
(Celeryと比較して)より近代的な解決策はDjango Qです。 https://Django-q.readthedocs.io/en/latest/index.html
それは素晴らしいドキュメンテーションを持っていて、よく聞きやすいです。 Windowsはプロセス分岐をサポートしていないため、Windowsサポートは欠けています。しかし、Windows for Linux Subsystemを使用して開発環境を作成すればうまくいきます。
私は今日あなたの問題と似たようなことをしました。
私はそれがサーバのtrhough cronによって扱われることを望んでいませんでした(そして、ほとんどのlibsは結局cronヘルパーでした)。
だから私はスケジューリングモジュールを作成し、initにそれを添付しました。
これは最善の方法ではありませんが、すべてのコードを1か所にまとめて実行し、その実行をメインアプリケーションに関連させるのに役立ちます。
はい、上記の方法はとても素晴らしいです。そしてそれらのいくつかを試しました。最後に、私はこのような方法を見つけました:
from threading import Timer
def sync():
do something...
sync_timer = Timer(self.interval, sync, ())
sync_timer.start()
再帰的と同じです。
わかりました、私はこの方法があなたの要求を満たすことができると思います。 :)
私は定期的な仕事をするためにセロリを使います。まず以下のようにインストールする必要があります。
pip install Django-celery
あなたの設定にDjango-celery
を登録することを忘れないでください。
from celery import task
from celery.decorators import periodic_task
from celery.task.schedules import crontab
from celery.utils.log import get_task_logger
@periodic_task(run_every=crontab(minute="0", hour="23"))
def do_every_midnight():
#your code
実際のサーバー(Windows)のタスクスケジューラにアクセスすることなく、ジョブをスケジュールするためにシステムの他のユーザーを提供しなければならなかったので、これがだれにも役立つことはわかりません。この再利用可能なアプリを作成しました。
ユーザーは必要なコマンド/ task/.batファイルを作成できるサーバー上の1つの共有フォルダにアクセスできます。このタスクは、このアプリを使ってスケジュールすることができます。
アプリ名は Django_Windows_Scheduler
Celery よりもtrustedが必要な場合は、TaskHawkを試してください。これはAWS SQS/SNSの上に構築されています。
参照してください: http://taskhawk.readthedocs.io
簡単な方法は、 Django Documentation を参照してカスタムのシェルコマンドを書き、それをlinuxのcronjobを使って実行することです。しかし、私はRabbitMQのようなメッセージブローカーとセロリを組み合わせることを強くお勧めします。多分あなたはこれを見てみることができます チュートリアル
単純なdockerizedプロジェクトでは、私は実際にはどんな既存の答えも適合するのを見ることができませんでした。
そこで私は、外部ライブラリやトリガーを必要とせずに、非常に必要最低限のソリューションを作成しました。外部のos-cronは必要ありません、あらゆる環境で動作するはずです。
ミドルウェアを追加することで動作します:middleware.py
import threading
def should_run(name, seconds_interval):
from application.models import CronJob
from Django.utils.timezone import now
try:
c = CronJob.objects.get(name=name)
except CronJob.DoesNotExist:
CronJob(name=name, last_ran=now()).save()
return True
if (now() - c.last_ran).total_seconds() >= seconds_interval:
c.last_ran = now()
c.save()
return True
return False
class CronTask:
def __init__(self, name, seconds_interval, function):
self.name = name
self.seconds_interval = seconds_interval
self.function = function
def cron_worker(*_):
if not should_run("main", 60):
return
# customize this part:
from application.models import Event
tasks = [
CronTask("events", 60 * 30, Event.clean_stale_objects),
# ...
]
for task in tasks:
if should_run(task.name, task.seconds_interval):
task.function()
def cron_middleware(get_response):
def middleware(request):
response = get_response(request)
threading.Thread(target=cron_worker).start()
return response
return middleware
models/cron.py
:
from Django.db import models
class CronJob(models.Model):
name = models.CharField(max_length=10, primary_key=True)
last_ran = models.DateTimeField()
settings.py
:
MIDDLEWARE = [
...
'application.middleware.cron_middleware',
...
]