web-dev-qa-db-ja.com

Django - スケジュールされた仕事を始めますか?

私はDjangoを使ってWebアプリを開発してきましたが、定期的に実行するようにジョブをスケジュールする方法があるかどうかに興味があります。

基本的には、データベースを調べて定期的に計算や更新を行いたいだけですが、これを実行するための資料が見つからないようです。

誰もがこれを設定する方法を知っていますか?

明確にするために:これを行うためにcronジョブを設定できることはわかっていますが、Djangoにこの機能を提供する機能があるかどうかは興味があります。私は人々が多くの設定(できれば0)をする必要なしに自分自身でこのアプリをデプロイできるようにしたいです。

前回サイトにリクエストが送信されてからジョブが実行されたかどうかを確認することで、これらのアクションを「遡及的に」実行することを検討しましたが、少しきれいなものを望んでいます。

472
TM.

私が採用した一つの解決策はこれをすることです:

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を同じ用途に使用できます。

331
Brian Neal

Celery はAMQP(RabbitMQ)上に構築された分散タスクキューです。また、cronのように周期的なタスクを処理します( 周期的なタスク を参照してください)。あなたのアプリによっては、それはガンダーの価値があるかもしれません。

CeleryはDjango( docs )を使って設定するのがとても簡単で、定期的なタスクは実際にはダウンタイムの場合に見逃したタスクをスキップします。タスクが失敗した場合に備えて、Celeryには再試行メカニズムも組み込まれています。

139
dln

私たちが構造化アプリだと思うものをオープンソース化しました。上記のBrianの解決策も暗示しています。すべてのフィードバックが大好きです。

https://github.com/tivix/Django-cron

管理コマンドが1つ付属しています。

./manage.py runcrons

それは仕事です。各cronはクラスとしてモデル化されているので(つまりすべてのオブジェクト指向)、各cronは異なる頻度で実行されます。同じcronタイプが並行して実行されないようにします(crons自体が実行頻度より時間がかかる場合)

ありがとうございます。

47
chachra

標準のPOSIX OSを使用している場合は、 cron を使用します。

Windowsを使用している場合は、 at を使用します。

Django管理コマンドを

  1. 彼らがどのプラットフォームにいるのか把握してください。

  2. ユーザーに適切な "AT"コマンドを実行するか、またはを使用してユーザーのcrontabを更新してください。

36
S.Lott

興味深い新しいプラガブルDjangoアプリ: Django-chronograph

タイマーとして機能するcronエントリを1つ追加するだけで済み、実行するスクリプトに非常に優れたDjango管理インターフェースがあります。

22
Van Gale

Django Poor Man's Cronを見てください。これは、スパムロボット、検索エンジンのインデックス作成ロボットなどを利用して、ほぼ定期的にスケジュールされたタスクを実行するDjangoアプリです。

参照してください。 http://code.google.com/p/Django-poormanscron/

14
user41767

RabbitMQとCeleryには、Cronよりも多くの機能とタスク処理機能があります。タスクの失敗が問題ではなく、次の呼び出しで壊れたタスクを処理すると思われる場合は、Cronで十分です。

Celery& AMQP は、壊れたタスクを処理できるようにし、タスクのmax_retries属性に到達しました。失敗をログに記録したり、max_retriesに達したら管理者にメールを送信するなど、失敗時にタスクを呼び出すこともできます。

また、アプリケーションを拡張する必要がある場合は、CeleryおよびAMQPサーバーを配布できます。

9
Ravi Kumar

Crianで管理コマンドを実行するというBrian Nealの提案はうまくいきますが、もう少し堅牢なものを探しているなら(まだCeleryほど精巧ではありません)、 Kronos :のようなライブラリを調べます。

# app/cron.py

import kronos

@kronos.register('0 * * * *')
def task():
    pass
9
Johannes Gorset

私は個人的にcronを使用していますが、 Jobs Scheduling の一部 Django-extensions はおもしろそうです。

8
Van Gale

私はしばらく前にまったく同じ要件を持っていて、 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

これが誰かに役立つことを願っています!

7
PhoenixDev

以下を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
6
Matt McCormick

私はちょうどこのかなり簡単な解決策について考えました:

  1. 他のビューと同様に、URLマッピングを使用してHttpResponseを返すなど、ビュー関数do_work(req、param)を定義します。
  2. curl http:// localhost/your/mapped)を実行するcronジョブを自分のタイミング設定で(またはWindowsではATまたはScheduled Tasksを使用して)設定します。/url?param = value

パラメータを追加することはできますが、URLにパラメータを追加するだけです。

皆さんの考えを教えてください。

[更新]curlの代わりに Django-extensions のrunjobコマンドを使っています。

私のcronはこんな感じです:

@hourly python /path/to/project/manage.py runjobs hourly

...など、毎日、毎月など。特定のジョブを実行するように設定することもできます。

私はそれがもっと管理しやすくてきれいであると思います。 URLをビューにマッピングする必要はありません。職種とcrontabを定義するだけで準備完了です。

6
Michael

Djangoには含まれていませんが、 Airflow はタスク管理に役立つ最近のプロジェクトです(2016年現在)。

エアフローは、データパイプラインを作成および管理するために使用できるワークフロー自動化およびスケジューリングシステムです。 WebベースのUIは、開発者にこれらのパイプラインを管理および表示するためのさまざまなオプションを提供します。

AirflowはPythonで書かれており、Flaskを使って構築されています。

AirflowはAirbnbのMaxime Beaucheminによって作成され、2015年の春にオープンソース化されました。2016年の冬にApache Software Foundationのインキュベーションプログラムに参加しました。 Gitプロジェクトページです といくつかの追加 背景情報

6
Alexander

コードの一部の後に、私の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/

4
xiaohei

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,
},
}
3
saran3h

(Celeryと比較して)より近代的な解決策はDjango Qです。 https://Django-q.readthedocs.io/en/latest/index.html

それは素晴らしいドキュメンテーションを持っていて、よく聞きやすいです。 Windowsはプロセス分岐をサポートしていないため、Windowsサポートは欠けています。しかし、Windows for Linux Subsystemを使用して開発環境を作成すればうまくいきます。

2
devdrc

私は今日あなたの問題と似たようなことをしました。

私はそれがサーバのtrhough cronによって扱われることを望んでいませんでした(そして、ほとんどのlibsは結局cronヘルパーでした)。

だから私はスケジューリングモジュールを作成し、initにそれを添付しました。

これは最善の方法ではありませんが、すべてのコードを1か所にまとめて実行し、その実行をメインアプリケーションに関連させるのに役立ちます。

2
Fabricio Buzeto

はい、上記の方法はとても素晴らしいです。そしてそれらのいくつかを試しました。最後に、私はこのような方法を見つけました:

    from threading import Timer

    def sync():

        do something...

        sync_timer = Timer(self.interval, sync, ())
        sync_timer.start()

再帰的と同じです。

わかりました、私はこの方法があなたの要求を満たすことができると思います。 :)

2
Ni Xiaoni

私は定期的な仕事をするためにセロリを使います。まず以下のようにインストールする必要があります。

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

スクリーンショット: enter image description here

1
just10minutes

Celery よりもtrustedが必要な場合は、TaskHawkを試してください。これはAWS SQS/SNSの上に構築されています。

参照してください: http://taskhawk.readthedocs.io

0
Sriram

簡単な方法は、 Django Documentation を参照してカスタムのシェルコマンドを書き、それをlinuxのcronjobを使って実行することです。しかし、私はRabbitMQのようなメッセージブローカーとセロリを組み合わせることを強くお勧めします。多分あなたはこれを見てみることができます チュートリアル

0
Hamfri

単純な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',
    ...
]
0
y-spreen