概要
RQ でプロセスハンドリングの挙動を確認してみました
環境
- macOS 11.7.10
- Python 3.11.6
- rq 1.16.1
サンプルコード
-
vim app.py
from datetime import timedelta
from redis import Redis
from rq import Queue
from rq_scheduler import Scheduler
from lib.util import Message
queue = Queue("default", connection=Redis(host="192.168.1.2"))
scheduler = Scheduler(queue=queue, connection=queue.connection)
scheduler.enqueue_in(timedelta(seconds=5), Message().say, msg="hello")
-
vim lib/util.py
import time
class Message:
def say(self, **kwargs):
print("Start say")
time.sleep(30)
print(kwargs)
-
pipenv run rq worker
-
pipenv run rqscheduler
-
pipenv run python app.py
10秒以内にワーカーを Ctrl+c で停止した場合
ワーカーがジョブを掴んでからワーカーのプロセスを停止しようとするとちゃんと最後まで処理が終了してからワーカーが停止しました
11:21:53 default: say(msg='hello') (4d5a4db9-e8c9-4ee3-b64c-1dd266e66068)
Start say
11:21:55 Worker 98f9aac6f73445f685d4f5588abd514f [PID 32100]: warm shut down requested
{'msg': 'hello'}
11:22:03 default: Job OK (4d5a4db9-e8c9-4ee3-b64c-1dd266e66068)
11:22:03 Result is kept for 500 seconds
11:22:03 Worker rq:worker:98f9aac6f73445f685d4f5588abd514f: stopping on request
11:22:03 Unsubscribing from channel rq:pubsub:98f9aac6f73445f685d4f5588abd514f
kill -9 した場合
ワーカーがジョブを実行中に kill -9 を送信してみました
その場合ワーカーは Warm shut down せずにすぐに終了してしまいます
12:05:54 default: say(msg='hello') (b4eac96d-9591-482c-9753-e3a9c150d83b)
Start say
zsh: killed pipenv run rq worker
redis 外部からアクセスできない場合
Protection mode が有効になっているので一旦無効にしましょう
- CONFIG SET protected-mode no
docker の場合
docker stop はデフォルトでは SIGTERM -> SIGKILL の順番で信号を送ります
SIGKILL までの時間は time というオプションで変更可能でデフォルトで10秒になります
ワーカーを docker 上で動かし docker stop した際のワーカーの挙動を確認します
- vim Dockerfile
FROM python:3.11.9-bullseye
COPY . /home
WORKDIR /home
RUN pip install pipenv
RUN pipenv install
CMD ["pipenv", "run", "rq", "worker", "--url", "redis://192.168.1.2:6379"]
- docker build -t worker .
-
docker create --name worker worker
- docker start worker
- docker logs -f worker
でワーカーを起動します
スケジューラとエンキューは python から行います
-
pipenv run rqscheduler
-
pipenv run python app.py
これでワーカーがジョブを実行中にワーカーコンテナを停止します
- docker stop worker
03:28:54 default: say(msg='hello') (76dbdc1b-5af2-4fa1-b4d2-49793454b235)
03:28:57 Worker 15c934ce3084457da63ade0e89ea14b6 [PID 1]: warm shut down requested
SIGTERM を受取り Warm shut down がスタートしますが10秒後に docker が強制的に SIGKILL を送信するためワーカーはジョブの完了を待たずに終了してしました
また強制終了したジョブは FailedJobRegistry に移動するようです
StartedJobRegistry cleanup: Moving job to FailedJobRegistry (due to AbandonedJobError)
time=60 にしてみる
SITTERM -> SIGKILL の送信にかかる時間を 60 秒に伸ばしてみます
-
docker stop --time=60 worker
すると今度はちゃんとワーカーがジョブの終了を待ってから停止していることが確認できました
03:32:54 default: say(msg='hello') (8e04f278-c5b1-4c4a-9069-3105960129f4)
03:33:14 Worker faa70ceee374410ba9416f55d74f4927 [PID 1]: warm shut down requested
Start say
{'msg': 'hello'}
03:33:25 default: Job OK (8e04f278-c5b1-4c4a-9069-3105960129f4)
03:33:25 Result is kept for 500 seconds
03:33:25 Worker rq:worker:faa70ceee374410ba9416f55d74f4927: stopping on request
03:33:25 Unsubscribing from channel rq:pubsub:faa70ceee374410ba9416f55d74f4927
最後に
RQ のシグナルハンドリングについて調べてみました
基本は RQ 側で実装されているので気にすることはないですが docker などと組み合わせる場合には SIGKILL の送信タイミングについて考慮する必要がありそうです
0 件のコメント:
コメントを投稿