---
# System prepended metadata

title: Extensions – JobQueue(翻譯)
tags: [bot, telegram]

---

# 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()
```


