Python WebAcademy

Python WebAcademy Blog

Celery 5.7がリリース。重い処理を裏で動かす定番ツールで、書き間違いや存在しない日付をその場で教えてくれるようになったニュースを初心者向けに解説

|

2026年11月5日、Pythonで重い処理を裏で動かすための定番ツールCeleryの5.7.0が公開されました。@shared_taskを2回重ねた書き間違いや、2月31日のような存在しない日付の定期実行を、その場でわかりやすいエラーにしてくれるようになり、たくさんの不具合も直っています。5.6.3と5.7.0で同じコードを動かした結果とともに整理します。

2026年11月5日、Pythonで重い処理を裏で動かすための定番ツールCeleryの5.7.0が公開されました。3月の5.6.3から、およそ7か月ぶりの新しい版です。

今回は、初心者がやりがちな書き間違いを、その場でわかりやすく教えてくれる変更が入っています。2月31日のように存在しない日付を定期実行に指定したときも、作った時点でエラーになるようになりました。

ほかにも、タスクの結果や定期実行まわりの不具合が、数多く直されています。今回は、5.6.3と5.7.0で同じコードを動かしながら、何が変わったのかを見ていきます。

まずはCeleryとはどんなものか

最初に、Celeryを知らない方のために、どんなツールなのかを簡単に紹介します。Celeryは、時間のかかる処理を、Webアプリの外で、別のプロセスに任せて動かすためのツールです。

たとえば、会員登録のときに確認メールを送る処理を考えてみてください。メールの送信を待ってから画面を返すと、利用者はしばらく待たされてしまいます。

タスクキューという仕組み

Celeryでは、裏で動かしたい処理をタスクとして定義し、メッセージを受け渡す仲介役のブローカーに預けます。それを、ワーカーと呼ばれる別のプロセスが取り出して、順番に実行します。

登場人物 役割
タスク 裏で動かしたい処理。Pythonの関数として書く
ブローカー タスクを預かる仲介役。RedisやRabbitMQがよく使われる
ワーカー ブローカーからタスクを取り出して、実行するプロセス
Beat 決まった時刻にタスクを送り出す、定期実行の仕組み

Webアプリは、タスクを預けたらすぐに画面を返せます。重い処理を裏に回すことで、利用者を待たせないアプリが作れるわけです。

最小のタスクを動かしてみた

実際に、メールを送ったことにするだけの小さなタスクを書いてみました。ここでは、ワーカーを使わずにその場で実行するapply()で、動きだけを確かめています。

from celery import Celery

app = Celery("shop", broker="memory://")


@app.task
def send_mail(to):
    return f"{to} さんにメールを送りました"


# ワーカーを使わず、その場で実行して動きを確かめる
result = send_mail.apply(args=("taro",))
print(result.get())

5.7.0を入れた仮想環境で、手元のPython 3.11で実行すると、taro さんにメールを送りましたと表示されました。実際のアプリでは、send_mail.delay("taro")のように呼んで、ワーカーに任せます。

@app.taskのように関数の上に書く記号は、デコレーターと呼ばれます。【関連記事】Pythonのデコレーターとは?

5.7で何が変わったのかを整理しよう

続いて、5.7.0の主な変更を表にまとめます。内容は、Celeryの公式リポジトリにある変更履歴Changelog.rstの、5.7.0とその前のアルファ版、ベータ版、候補版の記録にもとづいています。

分類 主な変更
書き間違いの検出 @shared_taskを2回重ねると、わかりやすいエラーに
定期実行 存在しない日付のcrontabを、作った時点で拒否
定期実行 1つの予定が失敗しても、Beat全体は止まらないように
結果の扱い タイムアウトに0を渡したとき、無限に待たないように
新機能 task-successのシグナルに、実行時間を追加

PyPIの記録によると、5.7.0は、9月22日のアルファ版、10月6日のベータ版、10月18日の候補版を経て公開されました。必要なPythonは、3.10以上です。

@shared_taskを2回重ねると、エラーで教えてくれる

まずは、初心者がやりがちな書き間違いから見ていきましょう。shared_taskは、特定のCeleryアプリに縛られないタスクを作るためのデコレーターで、Djangoと組み合わせるときによく使われます。

変更履歴によると、5.7.0からは、@shared_taskを同じ関数に2回付けると、わかりやすいエラーになるようになりました。

5.6.3と5.7.0で試してみた

うっかり、コピーして貼り付けたときに、デコレーターが2つ重なってしまった場面を再現しました。

from celery import shared_task


@shared_task
@shared_task
def add(x, y):
    return x + y

5.6.3と5.7.0を、それぞれ新しい仮想環境に入れて実行した結果です。

Celery 5.6.3
エラーは出ず、addはProxyという型のオブジェクトになった

Celery 5.7.0
TypeError: @shared_task was applied more than once to the same function. Remove the extra @shared_task decorator.

5.6.3では、エラーにならずに、そのまま読み込めてしまいました。5.7.0では、同じ関数に@shared_taskが2回付いているので、余計なほうを消すように、と直し方まで教えてくれます。

存在しない日付の定期実行を、作った時点で拒否

続いて、定期実行の変更です。Celeryには、cronと同じ書き方で、決まった日時にタスクを送り出すcrontabという仕組みがあります。

cronの書き方そのものについては、こちらで紹介しています。【関連記事】cronとは?

2月31日を指定してみた

変更履歴によると、5.7.0では、ありえない日付のcrontabを拒否するようになりました。実際に、2月31日の朝9時に実行する、という予定を作ってみます。

from celery.schedules import crontab

c = crontab(minute=0, hour=9, day_of_month=31, month_of_year=2)
print(c.remaining_estimate(c.now()))

実行した結果です。remaining_estimate()は、次に実行されるまでの残り時間を計算するメソッドです。

Celery 5.6.3
crontabは作成できた
RuntimeError: unable to rollover, time specification is probably invalid

Celery 5.7.0
ValueError: Invalid crontab: day_of_month 31 never occurs in month_of_year 2.

5.6.3では、予定そのものは作れてしまい、次の実行日時を計算しようとした段階で、わかりにくいエラーになりました。5.7.0では、作った時点で、31日は2月には存在しない、とはっきり教えてくれます。

なぜ嬉しいのか

5.6.3の動きでは、設定ファイルを書いた段階では何も起きず、Beatを動かしてから初めて問題が表に出ます。本番環境で、定期実行が動いていないことに後から気づく、という事態にもなりかねません。

変更履歴には、5.7.0では1つの予定が失敗しても、Beat全体は動き続けるようにしたとも書かれています。1つの間違いで、ほかの定期実行まで止まらないようになったのは、大きな安心材料です。

日付の扱いの基本は、こちらで紹介しています。【関連記事】Pythonのdatetimeとは?

timeout=0で、無限に待たなくなった

もう1つ、実際に試せた修正を紹介します。変更履歴によると、タスクの結果を待つときにtimeoutへ0を渡すと、これまでは時間切れにならず、待ち続けてしまうことがありました。

終わっていないタスクの結果を待ってみた

まだ誰も実行していないタスクの結果を、timeout=0で受け取ろうとするコードを用意しました。結果の保存先には、メモリ上のキャッシュを使っています。

import time

from celery import Celery
from celery.exceptions import TimeoutError

app = Celery("demo", broker="memory://", backend="cache+memory://")

# まだ誰も実行していない(終わっていない)タスクの結果を待つ
result = app.AsyncResult("not-finished-yet")
start = time.perf_counter()
try:
    result.get(timeout=0)
except TimeoutError:
    print("TimeoutError")
print(f"{time.perf_counter() - start:.1f}秒")

念のため、5秒たったら強制的に止めるようにして、2つの版で実行しました。

版 結果
5.6.3 何も表示されないまま待ち続け、5秒で強制的に止められた
5.7.0 すぐにTimeoutErrorになり、0.0秒と表示された

timeout=0は、待たずにすぐ確かめたい、という意味で使うことが多い書き方です。5.6.3では、それが逆に無限の待ちになっていたわけです。

そのほかの主な修正

5.7.0では、ほかにもたくさんの不具合が直されています。変更履歴から、初心者にも関係しそうなものを表にまとめます。

修正 中身
タイムアウトの0 結果を待つときに0を渡すと、無限に待っていたのを修正
結果の保存 成功を記録したあとに別の処理で失敗しても、失敗と記録しないように
取り消し ほかのワーカーが実行中のタスクを、取り消し済みにしないように
夏時間 太陽の位置にもとづく予定が、夏時間の切り替えでずれる問題を修正
結果の圧縮 result_compressionを設定しても、実際には圧縮されていなかった問題を修正

最後の結果の圧縮は、アルファ版の記録に書かれていた修正です。設定したつもりで、実は効いていなかったという種類の不具合でした。

新しいプロセスの作り方spawnにも対応

変更履歴によると、非同期のprefork、つまり複数のプロセスでタスクをさばく方式で、worker_pool_start_method='spawn'を指定できるようになりました。spawnは、新しいプロセスを、親の状態を引き継がずにまっさらな状態から始める方式です。

プロセスの作り方の違いについては、こちらで紹介しています。【関連記事】Pythonのmultiprocessingとは?

上げる前にやっておきたいこと

最後に、Celeryを5.7.0へ上げる前に確かめておきたいことを整理します。

順番 確認すること
1 Python 3.10以上を使っているか
2 @shared_taskが二重に付いている関数がないか
3 crontabに、存在しない日付の組み合わせを書いていないか
4 timeout=0が、すぐに時間切れになっても困らないか
5 ステージング環境で、ワーカーとBeatを一通り動かす

2と3は、5.6.3ではたまたま動いていたものが、5.7.0では起動時のエラーになる可能性があります。上げたらまず、ワーカーとBeatがきちんと起動するかを確かめましょう。

私は10年ほどエンジニアとして開発に関わってきましたが、月末に実行するつもりの定期処理を31日に設定してしまい、30日までしかない月に動かなかったことがあります。設定の段階で間違いに気づかせてくれる仕組みは、こうした事故を防いでくれます。

まとめ

2026年11月5日、Celery 5.7.0が公開されました。@shared_taskを2回重ねた書き間違いや、2月31日のような存在しない日付の定期実行を、その場でわかりやすいエラーにしてくれるようになり、結果や定期実行まわりの不具合もたくさん直っています。

裏で動く処理は、問題に気づきにくいものです。上げたあとは、ワーカーとBeatの起動を確かめ、定期実行がきちんと動いているかを見ておきましょう。

ここまでお読みいただきありがとうございました。

参考情報

次のアクション

記事で学んだ内容を実際に動かしてみよう

Python WebAcademyでは、ブラウザ上でコードを書きながら基礎から実践まで体系的に学べます。

Python WebAcademyの学習画面

あわせて読む

関連記事

ブログ一覧へ

Python学習ロードマップ

まずはこの3講座から

記事で気になったテーマを、順番に手を動かしながら学べます。

ロードマップを見る