# Extensions – JobQueue(翻譯) ###### tags: `telegram` `bot` >[name=shaoe.chen] :::danger [官方文件](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue) ::: [TOC] ## Introduction 擴展類別`telegram.ext.JobQueue`允許你以設置的間隔延遲,甚至週期性的執行任務。除此之外,你還可以用它向訂閱戶發送定期更新。 ## Usage 類別`JobQueue`與其它類別`telegram.ext`緊密結合在一起。就像是`Updater`與`Dispatcher`,它在單獨的執行緒中非同步的執行。 使用`JobQueue`並不需要做太多設置。當你實例化`Updater`的必的,它將為你建立一個`JobQueue`: ```python import telegram.ext from telegram.ext import Updater u = Updater('TOKEN', use_context=True) j = u.job_queue ``` 這個job_queue會同時連結到dispatcher,這文章後續會討論到。只要知道,除非你有很好的理由,否則不要自己實例化`JobQueue`。 工作隊列中的任務是由類別`Job`封裝。它有一個callback function做為參數,能夠在時間到來的時候執行。這個callback function始終帶著一個參數:`context`,一個`telegram.ext.CallbackContext`。就像是`Dispatcher`使用的程序處理callback一樣,透過這個物件,你可以訪問`context.bot`,也就是`Updater`的`telegram.Bot`的實例;而且在這特殊的情況下,你還可以訪問`context.job`,這是觸發callback的任務的`Job`實例(更多在說面說明)。 你可以使用下面三種方法來建立具有不同頻率與時間的工作:`job_queue.run_once`、`job_queue.run_repeating`與`job_queue.run_daily`。(正如之前所說,你通常不需要直接實例化類別`Job`) ## Tutorial 透過定義一個callback function並將它加入工作隊列來建立第一個工作到隊列。在這個教程中,你可以將`'@examplechannel'`替換為你的機器人是管理員的頻道,或是你的用戶id(使用[@userinfobot](https://telegram.me/userinfobot)來尋找你的用戶id): ```python def callback_minute(context: telegram.ext.CallbackContext): context.bot.send_message(chat_id='@examplechannel', text='One message every minute') job_minute = j.run_repeating(callback_minute, interval=60, first=0) ``` (如果你使用的是Python 2,請忽略類型的註解方式) 函數`callback_minute`將會每`60.0`秒執行一次,第一次就是現在(因為`first=0`)。參數`interval`與`first`如果是`int`或`float`的話,那就是以秒為單位。它們也可以是`datetime`物件。詳細資訊請參考[文件](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.jobqueue.html)說明。這些函數回傳的值是被建立的`Job`物件。如果沒有必要,你並不需要保存`run_repeating`(新實例化的`Job`)的結果;我們會在這個教程的後面使用它。你也可以增加一個執行一次而且會延遲的工作: ```python def callback_30(context: telegram.ext.CallbackContext): context.bot.send_message(chat_id='@examplechannel', text='A single message with 30s delay') j.run_once(callback_30, 30) ``` 三十秒之後你應該會接收到來自`callback_30`的訊息。 如果你厭倦每分鐘都收到訊息,你可以暫時關閉工作,甚至從隊列直接移除它。 ```python job_minute.enabled = False # Temporarily disable this job job_minute.schedule_removal() # Remove this job completely ``` **注意:** `schedule_removal`並不會立即從隊列中移除工作。而是將它標記為刪除,並在當前的間隔結束之後立即移除(標記刪除之後它將不會再執行)。 工作還可以改變自己的行為,因為它作為第二個參數傳給callback function: ```python def callback_increasing(context: telegram.ext.CallbackContext): job = context.job context.bot.send_message(chat_id='@examplechannel', text='Sending messages with increasing delay up to 10s, then stops.') job.interval += 1.0 if job.interval > 10.0: job.schedule_removal() j.run_repeating(callback_increasing, 1) ``` 這個工作會在一秒之後發送第一則訊息,再過兩秒發送第二則,再過三秒發送第三則,以此類推。在十則訊息之後它將自我終結。 你也許增加一個工作來回應某些使用者的輸入,有一個很方便的方法可以這麼做。如果你需要,所有的`Handler`類都可以傳遞工作隊列到它們的callback function。要做到這一點,你只需要在實例化`Handler`的時候設置`pass_job_queue=True`。你可以在這邊使用的另一個功能是`Job`的`context`關鍵參數。啟動工作的時候,你可以傳遞任何的物件做為下上文參數,在後續的階段只要工作存在就可以檢索它。讓我們看一下程式碼: ```python from telegram.ext import CommandHandler def callback_alarm(context: telegram.ext.CallbackContext): context.bot.send_message(chat_id=context.job.context, text='BEEP') def callback_timer(update: telegram.Update, context: telegram.ext.CallbackContext): context.bot.send_message(chat_id=update.message.chat_id, text='Setting a timer for 1 minute!') context.job_queue.run_once(callback_alarm, 60, context=update.message.chat_id) timer_handler = CommandHandler('timer', callback_timer) u.dispatcher.add_handler(timer_handler) ``` 透過放置`chat_id`在`Job`物件中,callback function就會知道它應該把訊息發送到那。 所有的好事都結束了,因此當你停止`Updater`的時候,相關的工作隊列也會同時停止: ```python u.stop() ``` 當然,你也可以自己停止隊列: ```python j.stop() ```