Python|Django+Apschedulerで二回実行される挙動の回避

DjangoはPythonでwebアプリを作る際の代表的なライブラリです。DjangoへApshedulerというライブラリ追加して、関数を定期的に自動実行します。また、私の環境ではセオリー通りにやると、関数が二回ずつ実行される症状が発生しました。この症状はrunserverに「–noreload」とオプションを付けることで回避できます。

  • VScodeでDjangoのプロジェクトスタートまで操作
  • Django + Apsheduler で定期実行を行う。
  • runserver –noreload」で、2回実行される挙動の回避

動作環境

本記事の動作環境は下記の通りです。

  • windows10
  • visualstudiocode1.73.1
  • python 3.8

プロジェクトの作成して開発用サーバーを起動

作業フォルダ(ワークスペース)の作成

VisualStudioCodeでDjangoプロジェクトを作成し、開発用サーバーを起動します。

「C:¥python¥test」というフォルダを作成し、作成したtestフォルダを右クリックし「Codeで開く」を選択します。

もし「Codeで開く」が表示されない場合はVisualStudioCodeを再インストールしましょう。これが表示されないと非常に不便です。

WindowsでVS CODEの「codeで開く」が表示されない場合の対処方法
今回の記事では上記のような疑問やお悩みに役立つ内容となっております。 WindowsでXAMPPなどを使いドキュメントルートを指定するときにそのまま右クリックで「codeで開く」から開きたいときってあ

仮想環境の構築

VisualStudioCodeが起動したら、次に仮想環境を構築します。

pythonはDjango以外にも様々なライブラリがあり、目的に合わせて使い分けが必要です。

仮想環境を構築せずに、いきなりDjangoやそのほかのライブラリをインストールすることもできます。この場合、ライブラリが増えてくると管理が大変で、何をインストールしたのかわからなくなってきます。使いたい用途に合わせてその都度、仮想環境を構築して、必要分だけライブラリをインストールする方が管理が簡単です。

VisualStudioCodeで「表示」→「ターミナル」と選択し、ターミナルを起動します。「C:python¥test>」と表示されるので、そこへ順番にコマンドを入力していきます。

まず下記のコマンドで仮想環境を構築します。「env」は仮想環境へつける名前なので、任意のもので結構です。「python」は環境によっては「python3」としないと動かない場合があります。

PS C:pythontest>python -m venv envCode language: CSS (css)

次に構築した仮想環境を有効化します。ターミナルに下記のコマンドを入力します。「env」は仮想環境につけた名前によって読み替えてください。

PS C:pythontest> .\env\Scripts\Activate.ps1Code language: CSS (css)

成功するとターミナルの左に「(env)」と表示されます。これは、envという仮想環境が有効になっていることを意味しています。

Djangoのインストール

続いて、djangoをインストールしていきます。

(env)PS C:pythontest> pip install djangoCode language: CSS (css)

コマンドを入力してしばらく待つと、Djangoのインストールに成功した旨のメッセージが表示されます。

下記のコマンドを入力し、インストールできているか確認します。

(env)PS C:pythontest> pip listCode language: CSS (css)

Djangoプロジェクトの作成と開発サーバーの起動

Djangoのプロジェクトを作成します。作成は以下のコマンドを打ち込むだけです。「testproject」は任意のもので構いません。ここで入力したものがプロジェクト名になります。成功すると、プロジェクトフォルダとその中の様々なファイルが生成されます。

(env)PS C:\python\test> django-admin startproject testproject

次に、作業フォルダをプロジェクトフォルダに変更します。下記のコマンドを入力し、「PS C:\python\test>」となっているところが「PS C:\python\test¥testproject」となればOKです。

(env)PS C:\python\test> cd .\testproject

次にアプリを作成します。下記のコマンドでアプリを作成します。成功すると、プロジェクトフォルダの中にアプリフォルダが生成されます。

(env)PS C:\python\test\testproject> python manage.py startapp testappCode language: CSS (css)

Djangoの開発用サーバーを起動します。下記のコマンドで開発用サーバーを起動します。この記事では、データベースの初期設定をしていないので赤文字で警告が表示されますが、データベースは使わないので無視します。

開発用サーバーの起動に成功すると、ターミナルに「Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK.」と表示されます。「http~」の部分をキーボードのコントロールボタンを押しながらクリックすると、webブラウザにロケットのアニメーションが表示されます。

開発用サーバーへのアクセスが成功しました。

サーバーを停止する場合は、VisualStudioCodeで「ctrl + c」を入力します。

(env)PS C:\python\test\testproject> django-admin .\manage.pyCode language: CSS (css)

Apschedulerのインストール

ターミナルに下記のコマンドを入力して「Apscheduler」をインストールします。インスト―ルに成功しているか否かは、「pip list」で確認できます。

(env)PS C:\python\test\testproject> pip install apscheduler
(env)PS C:\python\test\testproject> pip listCode language: PHP (php)

関数の定期実行の実装

関数の作成

簡単な関数を作成して、定期実行をテストしてみます。

「testapp」(アプリフォルダ)にapschedule.pyという名前でファイルを作成し、下記のコードを貼り付けます。

from datetime import datetime
from apscheduler.schedulers.background import BackgroundScheduler
# 現時刻をターミナルに出力する関数
def test_func():
    print ("時刻:" + str(datetime.now()) + "関数が実行されました。")
# 自動実行のための関数
def start():
    scheduler = BackgroundScheduler()
    scheduler.add_job(test_func, 'interval', minute=1)# 一分間隔で関数を実行
    scheduler.start()

参考:実行の間隔の書き方。

下の記述方法を真似すれば、定期的な実行の間隔を好きな時間、好きな間隔に変更できます。

# 5分おきに実行
scheduler.add_job(periodic_execution, 'interval', minutes=5)
# 1時間5秒おきに実行
scheduler.add_job(periodic_execution, 'interval', hours=1, seconds=5)
# 1日おきに実行
scheduler.add_job(periodic_execution, 'interval', days=1)
# 1週間おきに実行
scheduler.add_job(periodic_execution, 'interval', weeks=1)
# 2022年4月1日19時〜20時の間、1分おきに実行
scheduler.add_job(periodic_execution, 'interval', minutes=1,
    start_date="2022-04-01 19:00:00",
    end_date="2022-04-01 20:00:00")
# 毎時20分に実行
scheduler.add_job(periodic_execution, 'cron', minute=20)
# 月曜から金曜の間、22時になると実行
scheduler.add_job(periodic_execution, 'cron', hour=22, day_of_week='mon-fri')

このページから参考にさせていただきました。

【Django】自動で処理を定期実行する方法【APScheduler】
Djangoで処理を定期実行するには? APSchedulerの使い方とは? 本記事ではこのような疑問を解決します。 Webアプリ開発において、一定間隔orある時点において自動で処理を実行させたいシーンがあります。 例えば、一定間隔でデータ

apps.py とsetting.pyへ書き加え

「testapp」(アプリフォルダ)にapps.pyというアプリの設定ファイルがあります。ここへ定期実行のための記述を追記します。

from django.apps import AppConfig
class TestappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'testapp'
    def ready(self): # 追記 必ず既存のclassモジュールの中に記述する。インデントに注意
        from .apschedule import start #追記 インポート元として前述のapsheduleで作成したstart関数を指定する。
        start() #追記 インポートしたstart関数を実行

次に「testproject」(プロジェクトフォルダ)setting.pyにはアプリケーション追加します。

「setting.py」の中から「INSTALLED_APPS」の記述を探して、その中にアプリのConfigファイルを記述します。

どのDjangoの入門書に必ず書いてある、ごくごく一般的な記述です。

これで、Djangoを使った定期的な関数実行の準備が完了です。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'testapp.apps.TestappConfig', # アプリフォルダ内の「TestappConfig」を指定
]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

定期実行の動作確認

再び、「runserver」で開発用サーバーを立ち上げ、定期な自動実行の動作を確認しましょう。狙った通りに一分ごとに関数が実行され、ターミナルに時刻が表示されます。

ただし、私の環境の場合、一分ごとに関数が二回ずつ実行される事態になってしまいました。

runserverで定期実行が2回実行される挙動の回避

2回実行される原因

細かい理由はわかりませんが、Djangoのrunserverでは、プロセスが二つ立ち上がることに原因があるようです。

「– noreload」で2回実行される挙動を回避

この挙動は、開発用サーバーを立ち上げる際に「– noreload」とオプションを付けることで回避できます。

(test) PS C:\python\test\testproject> python manage.py runserver --noreloadCode language: CSS (css)

–noreloadオプションはこちらのブログにも開設がありました。

VScodeのデバックを使う場合

visual studio codeでDjangoの開発をする際は、デバック機能を活用して、開発用サーバーを立ち上げている人が多いかと思います。この場合は、デバックの設定が記述されている「launch.json」の記述を書き換える必要があります。

「configrations」→「args」 のリスト中に、「“–noreload”」を書き加えます。

これにより、デバック機能からrunserverをする場合でも、「–noreload」オプションを付けたことになります。

まとめ

この記事では、Djangoを使ったwebアプリで、定期的に関数を実行する方法を紹介しました。

・「Apscheduler」というライブラリを使えば、関数の定期的な実行が簡単にできる。

・定期的な実行を開発用サーバーでテストする場合は、「–noreload」オプションを付ける。

この二点を覚えておくとよいでしょう。

コメント

  1. whoiscall より:

    Thank you.

タイトルとURLをコピーしました