我正在嘗試在我的 python 中安排一些作業。假設,日志中的文本應該每 1 分鐘和每 5 分鐘從我的 docker 容器內的 jobs.py 檔案中出現。但是,文本在 docker 容器內每 2 分鐘出現一次。python schedule 和 cronjobs 之間是否存在沖突?
docker 容器內的當前輸出
13:05:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:05:00] "GET /reminder/send_reminders HTTP/1.1" 200 -
13:06:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:06:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
13:07:00 [D] schedule Running job Job(interval=1, unit=minutes, do=job_feeds_update, args=(), kwargs={})
13:07:00 [I] jobs job_feeds_update
13:07:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:07:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
13:08:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:08:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
13:09:00 [D] schedule Running job Job(interval=1, unit=minutes, do=job_feeds_update, args=(), kwargs={})
13:09:00 [I] jobs job_feeds_update
13:09:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:09:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
13:10:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:10:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
13:10:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:10:00] "GET /reminder/send_reminders HTTP/1.1" 200 -
13:11:00 [D] schedule Running job Job(interval=1, unit=minutes, do=job_feeds_update, args=(), kwargs={})
13:11:00 [I] jobs job_feeds_update
13:11:00 [D] schedule Running job Job(interval=5, unit=minutes, do=job_send_reminders, args=(), kwargs={})
13:11:00 [I] jobs job_send_reminders
服務器.py
#Cron Job
@app.route('/feeds/update_feeds')
def update_feeds():
schedule.run_pending()
return 'OK UPDATED FEED!'
@app.route('/reminder/send_reminders')
def send_reminders():
schedule.run_pending()
return 'OK UPDATED STATUS!'
作業.py
def job_feeds_update():
update_feed()
update_feed_eng()
logger.info("job_feeds_update")
schedule.every(1).minutes.do(job_feeds_update)
# send email reminders
def job_send_reminders():
send_reminders()
logger.info("job_send_reminders")
schedule.every(5).minutes.do(job_send_reminders)
碼頭工人檔案
FROM alpine:latest
# Install curlt
RUN apk add --no-cache curl
# Copy Scripts to Docker Image
COPY reminders.sh /usr/local/bin/reminders.sh
COPY feeds.sh /usr/local/bin/feeds.sh
RUN echo ' */5 * * * * /usr/local/bin/reminders.sh' >> /etc/crontabs/root
RUN echo ' * * * * * /usr/local/bin/feeds.sh' >> /etc/crontabs/root
# Run crond -f for Foreground
CMD ["/usr/sbin/crond", "-f"]
uj5u.com熱心網友回復:
我認為您遇到了幾個問題:
- 正如您所懷疑的,您
schedule的時間表/間隔與您的 cron 作業不同。它們不同步(你永遠不能指望它們會因為下一個原因而同步)。從jobs.py執行腳本的那一刻起,這就是計劃計算間隔的起點。
即,如果您每分鐘運行一次,但jobs.py腳本從當前分鐘的 30 秒開始(即 01:00:30 - 30 秒后的凌晨 1:00),那么調度程式將在 1:01:30 運行作業,然后是 1:02:30,然后是 1:03:30,以此類推。
Schedule不保證您精確的頻率執行。調度程式運行作業時,不考慮作業執行時間。因此,如果您安排諸如提要/提醒作業之類的作業,則可能需要一些時間來處理。一旦完成運行,調度程式決定下一個作業將僅在前一個作業結束后1 分鐘運行。這意味著您的執行時間可能會超出計劃。
嘗試在 python 腳本中運行這個示例,看看我在說什么
# Schedule Library imported
import schedule
import time
from datetime import datetime
def geeks():
now = datetime.now() # current date and time
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
time.sleep(5)
print(date_time "- Look at the timestamp")
geeks();
# Task scheduling
# After every 10mins geeks() is called.
schedule.every(1).seconds.do(geeks)
# Loop so that the scheduling task
# keeps on running all time.
while True:
# Checks whether a scheduled task
# is pending to run or not
schedule.run_pending()
time.sleep(0.1)
我們已安排該geeks函式每秒運行一次。但是如果你看一下 geeks 函式,我添加了一個time.sleep(5)來假裝這里可能有一些阻塞的 API 呼叫可能需要 5 秒。然后觀察記錄的時間戳 - 你會發現它們并不總是與我們最初想要的時間表一致!
現在看看你的 cron 作業和調度程式是如何不同步的
查看以下日志:
13:07:00 [D] schedule Running job Job(interval=1, unit=minutes, do=job_feeds_update, args=(), kwargs={})
13:07:00 [I] jobs job_feeds_update
13:07:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:07:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
# minute 8 doesn't trigger the schedule for feeds
13:09:00 [D] schedule Running job Job(interval=1, unit=minutes, do=job_feeds_update, args=(), kwargs={})
13:09:00 [I] jobs job_feeds_update
13:09:00 [I] werkzeug 172.20.0.2 - - [08/May/2022 13:09:00] "GET /feeds/update_feeds HTTP/1.1" 200 -
這里可能發生的情況如下:
在 13:07:00,您的 cron 發送請求以提供專案
在 13:07:00,作業計劃有一個用于提要專案的待處理作業
在 13:07:00:,作業完成并且計劃決定下一個作業只能在 1 分鐘后運行,大約是 ~13:08:01(注意 01,這是為了說明作業的毫秒/時間執行,假設運行提要專案更新需要 1 秒)
在 13:08:00,您的 cron 作業觸發了詢問
schedulerun_pending 作業的請求。但是,在 13:08:00時,沒有待運行的作業可以運行,因為下一次可以運行提要專案的時間是13:08:01,這不是現在。
在 13:09:00,您的 cron 選項卡再次觸發請求
在 13:09:00,有一個可用的待處理作業應該在13:08:01運行,以便現在執行。
我希望這能說明您在 cron 和 schedule 之間遇到的不同步問題。這個問題在生產環境中會變得更糟。您可以閱讀有關并行執行的更多資訊,以schedule作為一種使事情遠離主執行緒的方法,但這只會到此為止。讓我們來談談...
可能的解決方案
- 使用
run_allfrom schedule而不是run_pending強制觸發作業,無論它們何時實際安排。
但是如果你仔細想想,這與job_feeds_update直接從你的 API 路由本身呼叫沒有什么不同。這本身并不是一個壞主意,但它仍然不是超級干凈,因為它會阻塞 API 服務器的主執行緒,直到job_feeds_update完成,如果您有用戶需要的其他路由,這可能不是理想的。
您可以將其與下一個建議結合起來:
- 使用作業佇列和執行緒 查看調度檔案的并行執行頁面上的第二個示例。它向您展示了如何使用作業佇列和執行緒來卸載作業。
因為你 run schedule.run_pending(),你的服務器中的主執行緒被阻塞,直到作業運行。通過使用執行緒( 作業佇列),您可以繼續在佇列中調度作業 避免用您的作業阻塞主服務器。通過讓作業繼續被安排,這應該會為您進一步優化一些事情。
請改用它
ischedule,因為它考慮了作業執行時間并提供了精確的時間表:https ://pypi.org/project/ischedule/ 。如果 1 2 最終令人頭疼,這可能是最簡單的解決方案!不要使用計劃,而只是讓您的 cron 作業到達僅運行實際功能的路線(因此基本上與上面使用 1 2 的建議相反)。這樣做的問題是,如果您的函式需要超過一分鐘的時間來運行提要更新,您可能會同時運行多個重疊的 cron 作業來執行提要更新。所以我建議不要這樣做,而是依靠一種機制來對執行緒和作業的請求進行排隊/調度。僅將此作為您可以做的其他事情的潛在場景提及。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/471215.html
下一篇:容器未將資料寫入物理磁盤檔案
