Skip to content

Instantly share code, notes, and snippets.

@alazycoder101
Created March 26, 2025 21:07
Show Gist options
  • Save alazycoder101/620462768dfb2bdb6d4194d6b8dc387b to your computer and use it in GitHub Desktop.
Save alazycoder101/620462768dfb2bdb6d4194d6b8dc387b to your computer and use it in GitHub Desktop.

🛠️ API设计中的时间替代规则:原则与取舍

在现代预约系统中,时间管理是至关重要的环节。尤其在像 在线辅导平台 这样的场景中,教师可能会因临时事务、休假或其他原因,将原定的可预约时间替换为备用时间(alternative time)。如何在 API 中设计替代规则,既保证数据一致性,又简化客户端处理逻辑,同时保持扩展性,是我们要探讨的核心问题。


🎯 1. 问题定义与设计挑战

预约系统中,我们需要处理以下场景:

  • 教师预设了固定的可预约时间段
  • 教师临时调整,指定某个时间段不可用,但提供了替代时间
  • 学生在客户端查询可用时间时,不应看到无效时间
  • 需保证客户端缓存不会导致显示过期或无效的时间段

设计目标

  • 确保学生无法预约已被替代的时间段
  • 保持数据一致性,防止客户端缓存过期显示无效时间
  • 提供清晰、可扩展的 API,便于未来维护

🔍 2. 设计原则与取舍

原则一:服务端负责数据一致性

在涉及替代时间的场景中,数据一致性优先,因此服务端应负责处理替代逻辑。
原因:

  • 服务端具备全局视角,能够准确判断哪些时间段无效
  • 客户端缓存数据可能会滞后,导致显示过期时间
  • 简化客户端逻辑,减少客户端处理复杂性

结论:

  • 替代时间段应在服务端直接替换掉原时间段
  • 客户端只需展示有效时间段,无需关心替代逻辑

🚫 反面案例:客户端处理替代逻辑

做法:

  • 服务端返回常规时间 + 替代时间段
  • 客户端根据 is_replaced 标志位过滤无效时间

问题:

  • 增加客户端复杂性
  • 客户端缓存时间过长,可能导致显示已被替代的时间
  • 多端一致性难以保证

结论:

  • 将复杂的替代规则交给服务端处理,有助于保持数据一致性
  • 客户端只展示有效时间段,减少出错几率

🔥 3. API设计与实现

数据库设计

首先,我们设计数据表结构,记录常规时间和替代时间。

CREATE TABLE tutor_availability (
    id SERIAL PRIMARY KEY,
    tutor_id INT NOT NULL,
    date DATE NOT NULL,
    start_time TIME NOT NULL,
    end_time TIME NOT NULL,
    is_replaced BOOLEAN DEFAULT false,        -- 是否被替代
    alternative_start TIME,                   -- 替代时间段
    alternative_end TIME
);
  • is_replaced: 标记该时间段是否被替代
  • alternative_startalternative_end: 替代时间段

服务端API设计

查询有效时间段

  • 服务端在查询时合并替代时间段
  • 返回的时间段只包含有效时间

📌 SQL查询示例

-- 查询有效时间段(替代时间优先)
SELECT 
    tutor_id,
    date,
    COALESCE(alternative_start, start_time) AS start_time,
    COALESCE(alternative_end, end_time) AS end_time
FROM tutor_availability
WHERE date = '2025-04-01' 
  AND (is_replaced = false OR (alternative_start IS NOT NULL AND alternative_end IS NOT NULL));

返回结果

{
  "tutor_id": "67890",
  "date": "2025-04-01",
  "available_slots": [
    {
      "start_time": "2025-04-01T10:30:00Z",
      "end_time": "2025-04-01T11:30:00Z"
    }
  ]
}

服务端合并逻辑示例(Python伪代码)

def get_available_slots(tutor_id, date):
    slots = query_database(tutor_id, date)

    # 合并替代时间段
    available_slots = []
    for slot in slots:
        if slot['is_replaced'] and slot['alternative_start'] and slot['alternative_end']:
            # 替代时间段
            available_slots.append({
                "start_time": slot['alternative_start'],
                "end_time": slot['alternative_end']
            })
        elif not slot['is_replaced']:
            # 常规时间段
            available_slots.append({
                "start_time": slot['start_time'],
                "end_time": slot['end_time']
            })
    
    return available_slots

解释

  • 查询数据库时,将替代时间与常规时间合并
  • 服务端仅返回有效时间段

缓存处理:版本号机制

问题:客户端缓存可能导致数据不一致

  • 如果客户端缓存数据过久,可能导致显示过期时间段

解决方案

  • 服务端返回当前数据版本号
  • 客户端缓存数据时附带版本号
  • 每次查询时比较版本号,不一致时刷新数据

API 响应示例

{
  "version": "2025-04-01T10:00:00Z",   // 服务端数据版本
  "available_slots": [
    {
      "start_time": "2025-04-01T10:30:00Z",
      "end_time": "2025-04-01T11:30:00Z"
    }
  ]
}

客户端逻辑

  • 若客户端缓存版本号与服务端版本号一致,使用缓存数据
  • 若版本号不同,清理缓存,重新加载数据

⚙️ 4. 优化与扩展

① Redis缓存

  • 将教师可预约时间缓存至 Redis
  • 变更替代时间时,自动清理缓存
  • 减少数据库查询压力

② WebSocket实时通知

  • 教师修改时间后,实时通知客户端刷新数据
  • 减少客户端数据过期问题

③ 并发处理

  • 幂等性:使用 Idempotency-Key 防止重复预订
  • 乐观锁或事务,防止时间段被重复预订

🚀 5. 总结与最佳实践

选择服务端处理替代时间

  • 数据一致性更强,客户端只展示有效时间
  • 减少客户端逻辑复杂度

缓存版本号机制

  • 返回时间数据版本号,防止客户端缓存失效问题
  • 客户端判断版本号,保持数据同步

优化方向

  • Redis缓存时间段
  • WebSocket实时通知
  • 并发与幂等性处理

💡 通过服务端处理替代时间,我们不仅能保证数据一致性,还能简化客户端逻辑,减少缓存问题。同时,配合缓存优化和版本号校验,能确保学生在客户端看到的永远是有效时间段。 😎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment