問題1 - Sending due task
本機測試時沒有問題的,但是在線上 docker 中,任務一直顯示 “Sending due task”。超時的任務是 Django ORM update 操作。
猜測 - 是否與其他 Celery 公用了 redis db?
其他 Celery 也使用了這個 redis db 作為 broker,有很多其他 Celery 的任務在隊列中,輪不到我的任務。於是我將 redis db 設置為 13,但沒有修復這個問題。
使用隊列
那么我是否能夠定義一個自己的專有隊列,然后讓我的 worker 執行自定義隊列中的任務呢?這樣就不需要挑別人未使用的 redis db 了。
根據 http://docs.celeryproject.org/en/latest/userguide/routing.html#basics 以及 http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html 我將我的任務放在隊列中,然后報錯
ImproperlyConfigured:
Cannot mix new setting names with old setting names, please
rename the following settings to use the old format:task_routes -> CELERY_ROUTES
這是因為 Celery 有兩種命名規范。
New lowercase settings
Version 4.0 introduced new lower case settings and setting organization.The major difference between previous versions, apart from the lower case names, are the renaming of some prefixes, like celerybeat_ to beat_, celeryd_ to worker_, and most of the top level celery_ settings have been moved into a new task_ prefix.
Celery will still be able to read old configuration files, so there’s no rush in moving to the new settings format. - From http://docs.celeryproject.org/en/latest/userguide/configuration.html#example-configuration-file
在設置隊列后,還是沒有解決這個問題。
問題2 - 多個 docker 重復執行 Celery 任務
使用 docker 部署一次會創建三個容器,一個用作備份,兩外兩個用於生產。現在 Celery 會每小時向微信服務器申請 access token,然后就會被微信服務器封掉 ip,因為請求太頻繁了。
由於只要在本地的 access token 過期前申請新的 access token 就可以,所以不一定要在整點執行。於是我將申請 access token 的定時任務設置為隨機分鍾數,然后執行前檢查 redis,如果其他 docker 中的 Celery 已經執行過來,則不再執行。
問題3 - Not JSON serializable
錯誤信息:
kombu.exceptions.EncodeError: <function get_file_info at 0x1115c7bf8> is not JSON serializable
這是從 celery3.1.23 升級成 celery4.0.2 之后發生的,在我重新安裝 celery3.1.23 后就不會報錯。我搜索 kombu.exceptions.EncodeError not JSON serializable
、celery not JSON serializable
都沒有找到答案。
沒辦法之后,就問同事,剛開始他也沒思路,后來我強調 celery3.1.23 可以序列化而 celery4.0.2 會報錯,他突然想起:“celery4.0.2 默認使用 JSON 作為 serializer ,而 celery==3.1.23 默認使用 pickle。”。然后搜索 Add Celery serializer
,在 celeryconfig.py 中增加如下配置:
CELERY_TASK_SERIALIZER = 'pickle'
CELERY_RESULT_SERIALIZER = 'pickle'
CELERY_ACCEPT_CONTENT = ['pickle', 'json']
Celery 依賴問題
Celery 的依賴包不應該放進 requirements.txt 里面。因為當更換 Celery 版本的時候會導致依賴出問題。所以,不要將包的依賴放進 requirements.txt 中。
反思一下,存在以下問題:
- 升級之前沒有思考到庫的變化對代碼的影響,尤其是不兼容的版本版本升級(有 3.1.23 到 4.0.2)。
- 問人要提早問,不要不好意思。之前是問的太多了,現在是問的太少了。有些問題可能要花很多時間去找答案,但他人可能了解相關的知識,只要你提問足夠具體。