從「週期性任務」優化談起,一步步深入後端核心議題第一篇
前言
這個系列文章是以我的 side project “DoIt” 的尚未實作的功能——「週期性任務功能」為起點,模擬開發過程中可能遇到的問題,並延伸探討後端架構設計相關的議題,如資料庫設計、效能瓶頸、系統擴充與穩定性等。
🗓️ 摘要
在這篇文章中,我會紀錄我從 side project 中尚未實作的功能「週期性任務(Recurring Task)」當作情境並討論解決方案和問題。這是一個在 ToDo 類型應用中非常常見的功能,然而背後所需要處理的資料結構與效能考量,往往比想像中複雜。透過這個功能,我也會自然地延伸到一些更進階的主題:如快取、非同步、API 限流與資料一致性等。
graph TD
A[🗓️ 週期性任務功能探討
📦 資料庫設計 + 職責切分] --> B[🚀 快取設計實戰
🧠 避免重複計算]
B --> C[⏳ 非同步與背景任務處理
🛠️ 任務排程與延遲處理]
C --> D[📉 API 限流與防爆策略
🧱 避免同時大量操作導致崩潰]
D --> E[🧩 資料一致性與併發處理
🔒 Race condition & 加鎖處理]
週期性任務?
週期性任務指的是使用者可以建立一個會「每日」、「每週」、「每月」或「每年」重複出現的任務。舉例來說:每週一打掃房間、每個月繳房租、每年報稅等。
🏗️ 為了他,要做什麼更動?
這是我目前的結構,只能支援一般功能
🔧 前端
- 介面上需提供週期性任務的設定,例如重複頻率、結束時間等欄位
- 任務 model 的資料結構需要能夠攜帶週期性設定並傳送至後端
🧱 後端
- 各層(Controller → Service → Repository)需要能夠處理週期性任務的建立與管理
- 資料庫結構調整:
選項一:直接塞在原本 task
表裡
- 缺點:邏輯會變得複雜、不易維護
✅ 選項二:新增一個 recurring_task
表
這種做法更乾淨,可以讓 recurring 的邏輯獨立於一般任務,避免污染原始任務表。
範例 schema:
CREATE TABLE recurring_task (
id BIGINT PRIMARY KEY,
title VARCHAR(255),
description TEXT,
start_time TIMESTAMP,
user_id BIGINT,
recurrence_type ENUM('DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'),
recur_every INT,
end_time TIMESTAMP
);
- 如果要支援更複雜的重複規則(如每週一與週三),可以考慮:
- 儲存為 JSON 欄位(
repeat_pattern JSON
) - 或再開一張
recurrence_schedule
表來儲存規則細節
- 儲存為 JSON 欄位(
✨ 其他提升使用者體驗的功能
這樣的資料結構設計也方便之後延伸:
- 推播即將到期的週期任務
- 自動產生下一期任務
- 任務完成記錄管理(下一段會說)
🤔 前端每次都重新算週期任務?
直接在前端根據 recurring 設定去算下一次到期時間雖然可行,但效能上仍有一些考量:
- 使用者一多、任務一多、每次進入畫面都重新運算,效能不穩定
- 如果這個計算轉交給後端,在高併發下也可能造成負擔
那該怎麼辦?
核心目標:
✅ 減少即時計算(Reduce On-Demand Calculation)
✅ 將結果預算好、儲存下來,以空間換時間
📉 如何減少計算量
Lazy Loading(延遲載入)
- 像載入圖片一樣,先載入必要範圍
- 只在使用者需要看到某區段任務時才進行資料查詢與轉換
預先計算好並快取結果
- 後端定期(或使用者建立時)預計算好未來幾期的任務,並快取
- 前端從快取中讀取到期日與任務資訊,避免重複計算
✅ 任務完成怎麼處理?
使用者完成了週期性任務後,要避免「刷新後又變回未完成」的窘境。這代表我們需要記錄「這一次」的完成狀態。
做法:每一期都是一個獨立實體(順便解決上面計算問題)
參考 Microsoft To Do 的設計:
- 每個週期性任務都是獨立的實體,跟一般的 task 一樣
- 當一個週期性任務被完成,會移到已完成區域
- 同時產生下一期新的任務(根據 recurrence 計算)
好處:
- 看起來只有一個實體,每次完成會生出已完成的紀錄
- 顯示「已完成任務」時也能分期清楚列出
📌 下一篇將會延伸到「🚀 快取策略:讓網頁不卡卡的第一步」,探討各種快取與策略(例如 Redis 快取、前端快取策略)
從「週期性任務」優化談起,一步步深入後端核心議題第一篇
https://f88083.github.io/2025/04/18/從"週期性任務"優化談起 - 一步步深入後端核心議題第一篇/