第十章:自動化你的工作 - 在 FastAPI 實作 Cron Jobs 定時任務

當你的打卡系統上線運作了一個月,老闆把你叫進辦公室,開心地對你說:「系統很棒!但... 那個... 我每天晚上下班前,都要自己登入後台去點『匯出遲到名單』,有點麻煩。這個系統可以每天晚上 6 點,『自動』把今天遲到的人傳 Line 給我嗎?」

如果你不知道怎麼做「定時任務」,你可能會想到一個非常悲催的畫面:你設定了一個每天 5:55 的手機鬧鐘,時間一到,你就手動去敲擊鍵盤觸發 API。這聽起來一點都不像個工程師。

在現代化程式開發中,這件事有一個專屬的高級名詞:Cron Jobs (排程任務)。 它就像是軟體世界裡的「隱形鬧鐘」,時間一到,它就會在背景自動幫你做苦工。

🎯 本章目標

  1. 認識 Python 界最強的非同步排程套件 APScheduler
  2. 了解 FastAPI 的生命週期 (lifespan) 與背景任務的整合。
  3. 寫一個能自動 Query 資料庫,並透過 Line 主動發送通知的定時任務。

⏰ 第一步:安裝排程套件 (APScheduler)

Python 生態系有很多排程套件 (例如簡單的 schedule 或是龐大的 Celery),但在 FastAPI 這種主打「非同步 (Async)」的現代化框架中,業界最推薦使用的是輕量且支援非同步的 APScheduler

請開啟終端機 (記得啟動你的 venv!),輸入以下指令安裝:

pip install apscheduler

🚀 第二步:請 AI 寫出「每日遲到報表」腳本

在 FastAPI 裡面設定定時任務,最容易踩坑的地方在於「如何讓它跟著 FastAPI 的伺服器一起啟動,而不會互相卡死」。我們可以直接請 AI 用最新的 lifespan 寫法來實作。

🔥【Vibe Prompt 實戰咒語】 我正在開發一個 FastAPI 的 Line Bot。我需要加上一個定時排程任務 (Cron Job)。 需求如下: 1. 匯入 apscheduler 的 AsyncIOScheduler。 2. 寫一個非同步函數 daily_late_report(),設定在每天的傍晚 18:00 自動執行。 3. 在這個函數內部,請寫一段假邏輯:去資料庫撈出今天遲到的員工名單陣列,並組合成一段中文的匯報字串。 4. 使用 line-bot-sdk v3 的 api.push_message 功能,將這串匯報文字,主動推播給老闆 (請留一個 BOSS_LINE_ID 的變數給我填寫)。 5. (關鍵) 請將這個 Scheduler 正確地綁定在 FastAPI 最新版推薦的 lifespan (生命週期) 事件中啟動與關閉。

AI 生成的程式碼會非常優雅地整合在你的主程式中:

import os
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from fastapi import FastAPI
from contextlib import asynccontextmanager
from linebot.v3.messaging import Configuration, ApiClient, MessagingApi, PushMessageRequest, TextMessage

# 設定 Line 的金鑰與老闆的 ID
CHANNEL_ACCESS_TOKEN = os.getenv("LINE_CHANNEL_ACCESS_TOKEN")
BOSS_LINE_ID = os.getenv("BOSS_LINE_ID") # 老闆的 Line ID (通常以 U 開頭)

configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)

# 💼 定義要定時執行的核心任務
async def daily_late_report():
    print("⏰ [CronJob] 開始產生每日遲到報表...")
    
    # TODO: 這裡未來換成去 Supabase 資料庫撈取真實資料的語法
    late_users = ["王小明 (遲到 15 分鐘)", "李小華 (未打卡)"]
    
    if not late_users:
        report_text = "老闆您好,今日全體員工皆準時出勤,無人遲到!🎉"
    else:
        report_text = "老闆您好,今日出勤異常名單如下:\n\n" + "\n".join(late_users)
    
    # 透過 Messaging API 主動推播訊息給老闆
    try:
        with ApiClient(configuration) as api_client:
            line_bot_api = MessagingApi(api_client)
            line_bot_api.push_message(
                PushMessageRequest(
                    to=BOSS_LINE_ID,
                    messages=[TextMessage(text=report_text)]
                )
            )
        print("✅ [CronJob] 報表推播成功!")
    except Exception as e:
        print(f"❌ [CronJob] 推播失敗:{e}")

# 🔄 設定 FastAPI 的生命週期 (Lifespan)
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 伺服器啟動時:初始化並啟動鬧鐘
    scheduler = AsyncIOScheduler()
    # 每天 18 點 0 分執行 (可改成 "* * * * *" 來測試每分鐘執行)
    scheduler.add_job(daily_late_report, 'cron', hour=18, minute=0)
    scheduler.start()
    print("🕒 Scheduler 已啟動!排程任務待命中。")
    
    yield # 這裡代表 FastAPI 伺服器正在執行中...
    
    # 伺服器關閉時:優雅地關閉鬧鐘,釋放資源
    scheduler.shutdown()
    print("🛑 Scheduler 已安全關閉。")

# 啟動 FastAPI 應用程式
app = FastAPI(lifespan=lifespan)

有了這段程式,當你在伺服器上執行 uvicorn main:app 時,FastAPI 就會在背景默默地看著手錶倒數計時。 一到晚上六點整,不用任何人去點擊,老闆的手機就會叮咚一聲,收到熱騰騰的遲到名單。老闆會覺得你是一個無比專業、甚至會通靈的軟體供應商。


💼 [商業應用場景] 萬物皆可自動化

有了 Cron Job 這個「時間魔法」,你不只能做打卡系統的報表,你還可以開發出無數種可以收「月租費 (SaaS)」的自動化服務:

  1. 財務催繳機器人:每個月的 5 號,自動去資料庫把還沒繳月租費的客戶名單撈出來,發送 Line 的圖文卡片提醒他們繳款,甚至附上綠界的專屬繳款連結。
  2. 電商挽回購物車:如果使用者把商品加入購物車超過 24 小時未結帳,自動發送一組「限時 9 折優惠券」給他,提升轉換率。
  3. 每日天氣與運勢訂閱服務:每天早上 7:30,自動去中央氣象署抓取天氣 API,發送給所有訂閱的會員。

讓系統在半夜為你工作,這才是軟體工程師最浪漫的事情。下一章,我們將帶你進入伺服器部署的最後一塊拼圖,解決雲端平台對於 Cronjob 支援度不一的問題!

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!