從「週期性任務」優化談起,一步步深入後端核心議題第一篇

前言

這個系列文章是以我的 side project “DoIt” 的尚未實作的功能——「週期性任務功能」為起點,模擬開發過程中可能遇到的問題,並延伸探討後端架構設計相關的議題,如資料庫設計、效能瓶頸、系統擴充與穩定性等。

🗓️ 摘要

在這篇文章中,我會紀錄我從 side project 中尚未實作的功能「週期性任務(Recurring Task)」當作情境並討論解決方案和問題。這是一個在 ToDo 類型應用中非常常見的功能,然而背後所需要處理的資料結構與效能考量,往往比想像中複雜。透過這個功能,我也會自然地延伸到一些更進階的主題:如快取、非同步、API 限流與資料一致性等。



graph TD
  A[🗓️ 週期性任務功能探討
📦 資料庫設計 + 職責切分] --> B[🚀 快取設計實戰
🧠 避免重複計算] B --> C[⏳ 非同步與背景任務處理
🛠️ 任務排程與延遲處理] C --> D[📉 API 限流與防爆策略
🧱 避免同時大量操作導致崩潰] D --> E[🧩 資料一致性與併發處理
🔒 Race condition & 加鎖處理]

週期性任務?

週期性任務指的是使用者可以建立一個會「每日」、「每週」、「每月」或「每年」重複出現的任務。舉例來說:每週一打掃房間、每個月繳房租、每年報稅等。

🏗️ 為了他,要做什麼更動?

這是我目前的結構,只能支援一般功能

DB structure

🔧 前端

  • 介面上需提供週期性任務的設定,例如重複頻率、結束時間等欄位
  • 任務 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 表來儲存規則細節

✨ 其他提升使用者體驗的功能

這樣的資料結構設計也方便之後延伸:

  • 推播即將到期的週期任務
  • 自動產生下一期任務
  • 任務完成記錄管理(下一段會說)

🤔 前端每次都重新算週期任務?

直接在前端根據 recurring 設定去算下一次到期時間雖然可行,但效能上仍有一些考量:

  • 使用者一多、任務一多、每次進入畫面都重新運算,效能不穩定
  • 如果這個計算轉交給後端,在高併發下也可能造成負擔

那該怎麼辦?

核心目標:

✅ 減少即時計算(Reduce On-Demand Calculation)

✅ 將結果預算好、儲存下來,以空間換時間

📉 如何減少計算量

Lazy Loading(延遲載入)

  • 像載入圖片一樣,先載入必要範圍
  • 只在使用者需要看到某區段任務時才進行資料查詢與轉換

預先計算好並快取結果

  • 後端定期(或使用者建立時)預計算好未來幾期的任務,並快取
  • 前端從快取中讀取到期日與任務資訊,避免重複計算

✅ 任務完成怎麼處理?

使用者完成了週期性任務後,要避免「刷新後又變回未完成」的窘境。這代表我們需要記錄「這一次」的完成狀態。

做法:每一期都是一個獨立實體(順便解決上面計算問題)

參考 Microsoft To Do 的設計:

  • 每個週期性任務都是獨立的實體,跟一般的 task 一樣
  • 當一個週期性任務被完成,會移到已完成區域
  • 同時產生下一期新的任務(根據 recurrence 計算)

好處:

  • 看起來只有一個實體,每次完成會生出已完成的紀錄
  • 顯示「已完成任務」時也能分期清楚列出

📌 下一篇將會延伸到「🚀 快取策略:讓網頁不卡卡的第一步」,探討各種快取與策略(例如 Redis 快取、前端快取策略)