## 5. Inbox 处理与最佳实践

### 5.1 Inbox 概念

- Inbox 是特殊 namespace(`_inbox`),Area 固定为 00
- 快速捕获的内容默认进入 Inbox,状态为 unprocessed
- Inbox 中的资源无需完整,支持最小化输入

### 5.2 处理操作

| 操作 | 说明 | 命令 |
|------|------|------|
| 归类 (Refile) | 移动到目标 namespace,分配 Area.Category | syn inbox move <id> --to <ns> --type <type> |
| 转换 | 转换资源类型(如 note → task) | syn inbox convert <id> --type task |
| 归档 | 原地标记 status=`archived`,不移动文件 | syn inbox archive <id> |
| 删除 | 永久删除(Git 可恢复) | syn inbox delete <id> |

**归档说明**:
- 归档操作**不移动文件**,仅修改 Frontmatter 中的 status 字段为 archived
- 归档后的资源在列表中默认隐藏,可通过 --include-archived 显示
- 如需移动到特定归档目录,应使用 syn inbox move --to archive-namespace
- **`unprocessed` 类型特殊处理**:由于 unprocessed 状态不可变,归档时自动转换为 note 类型并标记 status=archived

  syn inbox archive 00.000.0001
  # unprocessed → note (status=archived)
  # 文件重命名:00.000.0001-unprocessed-xxx.md → 00.000.0001-note-xxx.md
  


### 5.3 Inbox 处理最佳实践(GTD 风格)

处理流程决策树:


                    ┌─────────────┐
                    │  Inbox 项目  │
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │ 这是什么?   │
                    │ 需要行动吗? │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
         ┌────▼────┐  ┌────▼────┐  ┌────▼────┐
         │  不需要  │  │ 需要行动 │  │ 参考资料 │
         └────┬────┘  └────┬────┘  └────┬────┘
              │            │            │
         ┌────▼────┐       │       ┌────▼────┐
         │  删除   │       │       │ 归类为  │
         │  或归档  │       │       │  note   │
         └─────────┘       │       └─────────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
         ┌────▼────┐  ┌────▼────┐  ┌────▼────┐
         │ < 2分钟  │  │ 委派他人 │  │ 需要规划 │
         │ 立即做! │  │         │  │         │
         └────┬────┘  └────┬────┘  └────┬────┘
              │            │            │
         ┌────▼────┐  ┌────▼────┐  ┌────▼────┐
         │ 完成后   │  │ 创建任务 │  │ 创建任务 │
         │ 归档/删除│  │ 分配给   │  │ 设置    │
         └─────────┘  │ 他人     │  │ 截止日期 │
                      └─────────┘  └─────────┘


最佳实践规则:

1. **2 分钟规则**:如果一件事 2 分钟内能完成,立即做,不要放入任务列表
2. **每日清空**:每天至少处理一次 Inbox,目标是 Inbox Zero
3. **快速决策**:每个项目只处理一次,立即决定其去向
4. **最小化输入**:捕获时只记录关键信息,处理时再补充细节

处理快捷流程:


# 批量处理 Inbox
syn inbox process

# 交互式处理(逐项显示,提供操作选项)
# [m]ove | [c]onvert | [a]rchive | [d]elete | [s]kip

# 快速转换为任务
syn inbox convert <id> --type task --due tomorrow --priority high

# 快速归类
syn inbox move <id> --to work-project --type meeting


TUI Inbox 处理快捷键:

| 快捷键 | 操作 | 说明 |
|--------|------|------|
| Enter | 查看详情 | 与全局快捷键一致 |
| e | 编辑后处理 | 打开编辑器,关闭后弹出处理选项 |
| m | 移动(Refile) | 层级菜单选择目标位置 |
| t | 快速转换为 task | 一键转换,保留原位置 |
| a | 归档 | 标记 status=archived |
| d | 删除 | 永久删除(Git 可恢复) |

### 5.4 Refile 交互优化(类似 Emacs Org-mode)

m (move) 是最高频操作,TUI 实现层级菜单式 Refile:
┌─────────────────────────────────────────────┐
@work-project/20 │ ← 范围搜索
├─────────────────────────────────────────────┤
│ 显示 work-project namespace Area 20 资源 │
└─────────────────────────────────────────────┘


### 4.5 上下文感知交互

| 视图 | `Enter` | `Space` | `e` |
|------|---------|---------|-----|
| Task 列表 | 查看详情 | 切换 status: `todo` → `in-progress` → `done` | 编辑 |
| Meeting 列表 | 查看详情 | 切换 status: `scheduled` ↔ `completed` | 编辑 |
| Email 列表 | 查看详情 | 切换 status: `unread` → `read` → `replied` | 编辑 |
| Note 列表 | 查看详情 | (无活跃状态循环,使用 `a` 键归档) | 编辑 |
| Calendar (日) | 资源详情 | 同上(根据资源类型) | 新建事项 |
| Inbox | 查看详情 | (unprocessed 状态不可切换) | 编辑后处理 |

**Space 状态循环**(仅限活跃状态):
- Task: `todo` → `in-progress` → `done` → `todo`
- Meeting: `scheduled` ↔ `completed`(二元切换)
- Email: `unread` → `read` → `replied` → `unread`
- Note: **无 Space 循环**(仅有 `active`/`archived` 两态,使用 `a` 键切换)

**终态处理**(`archived` / `cancelled`):
- `archived` 和 `cancelled` 是**终态**,不参与 Space 循环
- 当资源处于终态时,Space 键**无响应**(或显示提示"资源已归档/取消")
- 进入/退出终态:使用 `a` 键(归档/取消归档)或编辑 Frontmatter

| 状态 | 类型 | 进入方式 | 退出方式 |
|------|------|----------|----------|
| `archived` | task, email | `a` 键归档 | `a` 键取消归档(恢复到 `todo`/`unread`) |
| `archived` | note | `a` 键归档 | `a` 键取消归档(恢复到 `active`) |
| `cancelled` | meeting | 编辑 status 字段 | 编辑 status 字段 |

**`a` 键行为**:
- 活跃状态 → `archived`(归档)
- `archived` → 恢复到默认活跃状态(task→`todo`, email→`unread`, note→`active`)

### 4.6 编辑器配置

| 平台 | 默认 | 可选 |
|------|------|------|
| Windows | notepad | typora, vscode |
| Linux | vim | typora |
| macOS | vim | typora |

### 4.7 日历视图

**时间来源**:
- task: `due` / `start_date`
- meeting: `datetime` / `duration`

**条带说明**:每个条带代表一个资源,高度表示时间跨度,颜色表示类型/优先级。

**交互**:
- `↑↓` 在同一天的条带间切换选中
- `←→` 在日期间导航
- 选中条带时,底部显示资源摘要
- `Enter` 查看资源详情


Calendar - Week (2024-W03) [personal]
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│ Mon 15 │ Tue 16 │ Wed 17 │ Thu 18 │ Fri 19 │ Sat 20 │ Sun 21 │
├────────┼────────┼────────┼────────┼────────┼────────┼────────┤
│ ▓▓▓▓ │ ██ │ ▓▓▓▓▓▓ │ ████ │ ██ │ │ │
│ ████ │ │ ▓▓▓▓ │ ▓▓ │ │ │ │
├────────┴────────┴────────┴────────┴────────┴────────┴────────┤
[Wed 14:00] 项目评审会议 (meeting) - 14:00~16:00 │
│ Attendees: @alice, @bob │
└──────────────────────────────────────────────────────────────┘
[↑↓] Select [←→] Navigate [Enter] Details [w/m] Week/Month [q] Back

图例:▓▓ = meeting (紫色) ██ = task (蓝色) ░░ = note (灰色)


**跨天显示**:start_date 到 due 的任务、跨天会议,在每天都显示连续条带。

### 4.8 时间线视图

**时间来源**:Git commit 时间戳(资源的 `modified` 时间)

**条带说明**:每列代表一天,条带高度表示当天活动密度,每个条带对应一次 commit。

**交互**:
- `←→` 在时间轴上导航
- `↑↓` 在同一天的 commit 间切换
- 选中 commit 时,底部显示 commit 信息和涉及的资源
- `Enter` 跳转到该资源


Timeline - Last 7 Days [personal]
─────┬──────┬──────┬──────┬──────┬──────┬──────┬─────────
│ ▓▓ │ ████ │ ██ │ ████ │ ▓▓ │██████│ ██
│ ████ │ ▓▓ │ ████ │ ██ │ ████ │ ▓▓▓▓ │ ████
─────┴──────┴──────┴──────┴──────┴──────┴──────┴─────────
Mon Tue Wed Thu Fri Sat Sun

[Sun 14:32] feat(task): add new task for review
10.001.0015-task-完成项目设计.md
──────────────────────────────────────────────────────────
[↑↓] Select [←→] Navigate [Enter] Resource [d/w/m/y] Scale [q] Back

图例:▓▓ = meeting ██ = task ░░ = note (颜色同日历视图)


### 4.9 会话持久化(Session Persistence)

系统在 `.synapse/session.json`(不入 Git)中记录当前上下文状态:

```json
{
  "last_active_namespace": "work-project",
  "namespaces": {
    "personal": {
      "last_view": "calendar",
      "selected_date": "2024-01-20",
      "recent_files": ["10.001.0001", "10.002.0005"]
    },
    "work-project": {
      "last_view": "list",
      "filter_state": {"status": "todo", "tag": "urgent"},
      "recent_files": ["20.001.0003"]
    }
  },
  "global_history": [
    "syn show 10.001.0001",
    "syn search kubernetes"
  ]
}


**行为**:
- 启动 syn 时,自动恢复到上次退出的 Namespace 和 View
- Ctrl+Tab 可在最近打开的两个文件/视图间快速切换
- 每个 Namespace 独立记录筛选状态和最近文件

---
workspace/
├── .synapse/                              # 系统目录
│   ├── config.yaml                       # 全局配置
│   ├── index.db                          # SQLite 索引
│   └── hooks/                            # Git hooks
├── personal/                              # namespace
│   ├── .synapse.yaml                     # namespace 配置
│   ├── 10/                               # Area 10: 个人管理
│   │   ├── 001/                          # Category 001: 任务
│   │   │   ├── 10.001.0001-task-完成报告.md
│   │   │   └── 10.001.0002-task-学习计划.md
│   │   └── 002/                          # Category 002: 笔记
│   │       └── 10.002.0001-note-学习笔记.md
│   └── 11/                               # Area 11: 会议
│       └── 001/
│           └── 11.001.0001-meeting-周会.md
├── work-project/
│   ├── .synapse.yaml
│   └── 20/
│       └── 001/
│           ├── 20.001.0001-meeting-需求评审.md
│           └── 20.001.0002-task-开发任务.md
└── _inbox/                                # 特殊 namespace
    └── 00/
        └── 000/                          # Inbox 固定使用 00.000
            ├── 00.000.0001-unprocessed-快速记录.md
            └── 00.000.0002-unprocessed-临时想法.md


**设计说明**:
- **双层分桶**:Area → Category,避免单目录大量文件
- 每个 Category 目录最多 9999 个文件,人眼可管理
- 查询走 SQLite 索引,目录层级不影响性能
- Area/Category 子目录由系统自动创建

---

## 4. 用户界面

### 4.1 统一命令设计

CLI 和 TUI 使用统一的命令/操作命名:

| 操作 | CLI 命令 | TUI 快捷键 | 说明 |
|------|----------|------------|------|
| 新建 | syn new [type] | n | 创建新资源 |
| 列表 | syn list [type] | l | 列表视图 |
| 查看 | syn show <id> | Enter | 查看详情 |
| 编辑 | syn edit <id> | e | 编辑资源 |
| 删除 | syn delete <id> | d | 删除资源 |
| 搜索 | syn search <query> | / | 搜索过滤 |
| 日历 | syn calendar | c | 日历视图 |
| 时间线 | syn timeline | t | 时间线视图 |
| 图谱 | syn graph | g | 图谱视图 |

### 4.2 CLI 命令示例


# TUI 启动
syn

# 资源操作
syn new task --title "完成设计" --priority high --due 2024-01-15
syn new note --title "会议记录"
syn list task --status todo
syn show 10.001.0015        # 完整 ID
syn show 10.1.15            # 短 ID(自动补零)
syn show 15                 # 最短 ID(当前 Namespace 内唯一)
syn edit 10.001.0015
syn delete 10.001.0015
syn search "kubernetes" --type note --tag devops

# Inbox 操作
syn inbox list
syn inbox process
syn inbox move <id> --to <namespace> --type <type>

# 回顾操作
syn review daily
syn review weekly

# Namespace 操作
syn ns list
syn ns new my-project
syn ns switch work-project


### 4.3 TUI 快捷键

| 快捷键 | 功能 |
|--------|------|
| n | 新建资源 |
| e | 编辑(外部编辑器) |
| d | 删除 |
| a | 归档/取消归档(切换 archived 状态) |
| / | 搜索/Fuzzy Finder |
| Enter | 查看详情 |
| Space | 切换活跃状态(见 §4.5 状态循环) |
| r | 刷新 |
| q | 退出/返回 |
| ? | 帮助 |
| Ctrl+P | 命令面板 |
| l | 列表视图 |
| c | 日历视图 |
| t | 时间线视图 |
| g | 图谱视图 |
| 0 | 切换到 Inbox |
| 1-9 | 切换 Namespace |

### 4.4 命令面板 (Command Palette)

参考 VS Code / Obsidian 的交互逻辑,区分不同模式:

| 快捷键 | 模式 | 功能 |
|--------|------|------|
| Ctrl+P | 文件跳转 | Fuzzy Search Title/ID |
| Ctrl+Shift+P> | 命令执行 | 执行命令 |
| # | Tag 搜索 | 按标签过滤 |
| @ | 范围搜索 | 按 Namespace/Area 过滤 |

**交互示例**:
`
┌─────────────────────────────────────────────┐
│ 设计文档 │ ← 默认:文件跳转
├─────────────────────────────────────────────┤
│ 10.001.0015 - 完成项目设计 │
│ 10.002.0003 - 设计规范笔记 │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ > review │ ← 命令模式
├─────────────────────────────────────────────┤
│ syn review daily │
│ syn review weekly │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
#urgent │ ← Tag 搜索
├─────────────────────────────────────────────┤
│ 10.001.0015 - 紧急任务 [urgent, work] │
└─────────────────────────────────────────────┘
def allocate_next_id(namespace: str, area: str, category: str) -> str:
    """
    原子分配下一个可用 ID
    使用 IMMEDIATE 事务模式 + UNIQUE 约束确保并发安全
    """
    max_retries = 3
    for attempt in range(max_retries):
        try:
            # ⚠️ 关键:使用 IMMEDIATE 模式,事务开始时立即获取写锁
            # 这会阻塞其他写事务,避免空 Category 的竞态条件
            cursor.execute("BEGIN IMMEDIATE")
            
            # 1. 查询当前 Category 下最大 ID
            # 同时查询 id_reservations 表(可能有预占但未使用的 ID)
            cursor.execute("""
                SELECT MAX(id_num) FROM (
                    SELECT CAST(SUBSTR(jd_number, -4) AS INTEGER) as id_num
                    FROM resources 
                    WHERE namespace = ? AND jd_number LIKE ?
                    UNION ALL
                    SELECT CAST(SUBSTR(jd_number, -4) AS INTEGER) as id_num
                    FROM id_reservations
                    WHERE namespace = ? AND jd_number LIKE ?
                )
            """, (namespace, f"{area}.{category}.%", 
                  namespace, f"{area}.{category}.%"))
            
            row = cursor.fetchone()
            max_id = (row[0] if row else None) or 0
            next_id = max_id + 1
            
            if next_id > 9999:
                cursor.execute("ROLLBACK")
                raise OverflowError(f"Category {area}.{category} ID exhausted (max 9999)")
            
            # 2. 预占 ID(UNIQUE 约束是最后一道防线)
            new_jd = f"{area}.{category}.{next_id:04d}"
            cursor.execute("""
                INSERT INTO id_reservations (jd_number, namespace, reserved_at)
                VALUES (?, ?, datetime('now'))
            """, (new_jd, namespace))
            
            cursor.execute("COMMIT")
            return new_jd
            
        except sqlite3.IntegrityError:
            # UNIQUE 约束冲突,说明有并发分配,重试
            cursor.execute("ROLLBACK")
            if attempt == max_retries - 1:
                raise AllocationError(f"Failed to allocate ID after {max_retries} retries")
            continue  # 重试

def release_reservation(jd_number: str):
    """创建失败时释放预占的 ID"""
    cursor.execute("DELETE FROM id_reservations WHERE jd_number = ?", (jd_number,))


**id_reservations 表结构**:


CREATE TABLE id_reservations (
    jd_number TEXT PRIMARY KEY,   -- ⚠️ UNIQUE 约束,防止重复分配
    namespace TEXT NOT NULL,
    reserved_at TEXT NOT NULL,
    INDEX idx_namespace_jd (namespace, jd_number)
);

-- 定期清理过期预占(超过 1 小时未使用)
DELETE FROM id_reservations 
WHERE reserved_at < datetime('now', '-1 hour');


**并发控制机制**:

| 层级 | 机制 | 作用 |
|------|------|------|
| 1 | BEGIN IMMEDIATE | 事务级写锁,阻塞其他写事务 |
| 2 | 查询含 id_reservations | 感知其他进程的预占 |
| 3 | jd_number PRIMARY KEY | UNIQUE 约束,最后防线 |
| 4 | 重试机制 | 冲突时自动重试 |


**批量导入优化**:

```bash
# 批量模式:一次性预占 N 个 ID,减少锁竞争
syn import --batch /path/to/files/ --count 100

# 内部实现:单次事务分配 100 个连续 ID


**ID 耗尽处理**:
- 每个 Category 最多 9999 个资源
- 接近上限(>9000)时 CLI/TUI 显示警告
- 建议用户创建新 Category 或清理归档资源

### 3.2 短 ID 支持

为降低 CLI 输入摩擦,支持 Git 风格的短 ID:

| 输入方式 | 示例 | 匹配规则 |
|----------|------|----------|
| 完整 ID | 10.001.0015 | 精确匹配 |
| 短 ID | 10.1.15 | 自动补零 → 10.001.0015 |
| 最短 ID | 15 | 当前 Namespace 内唯一匹配 |
| 标题模糊 | 设计文档 | Fuzzy Finder 模糊搜索 |


syn show 15           # 当前 Namespace 内唯一,直接匹配
syn show 10.1.15      # 自动补零
syn show 设计         # Fuzzy Finder


**歧义处理**:当短 ID 匹配到多个结果时:
- **CLI**:报错并列出候选项,用户需输入更精确的 ID
- **TUI**:弹窗让用户选择


$ syn show 15
Error: Ambiguous ID '15'. Did you mean:
  [1] 10.001.0015 - 完成项目设计 (task)
  [2] 20.001.0015 - 会议纪要 (meeting)
Use full ID or choose: syn show 10.001.0015


**Shell 自动补全**:CLI 必须实现 Tab completion(支持 Bash/Zsh/Fish)。

### 3.3 目录结构(双层分桶)
# Synapse (syn) - 需求规格说明书

> Synapse - 神经突触,象征知识连接与传递。缩写 syn 简短易记,与知识管理高度契合。

---

## 1. 引言

### 1.1 系统愿景

Synapse 是一个基于 Python 3 构建的命令行/TUI 工作流管理工具,提供统一的知识与任务管理平台。

核心理念: "快速捕获、清晰组织、经常回顾、有效执行" (CORE)

### 1.2 核心原则

| 原则 | 描述 |
|------|------|
| 快速捕获 | 最小化录入摩擦,新内容默认进入 Inbox |
| 清晰组织 | Johnny.Decimal 变体 + k8s 风格资源管理 |
| 经常回顾 | GTD、周期性和智能回顾模式 |
| 有效执行 | 任务跟踪、状态管理、自动化工作流 |

### 1.3 目标用户

- **个人用户**:知识管理、任务追踪
- **团队用户**:协作、项目管理
- 支持个人使用,可扩展到团队协作

### 1.4 技术栈

| 组件 | 选型 | 说明 |
|------|------|------|
| TUI | Textual | CSS 布局,鼠标支持,适合 k9s 风格 |
| 存储 | Markdown | 仅 .md 文件,禁止二进制 |
| 索引 | SQLite + FTS5 | Sidecar Index,加速查询 |
| 搜索 | Ripgrep | 全文搜索,高性能 |
| 文件监听 | watchdog | 实时检测外部修改 |
| 版本控制 | Git | 本地 + 远程 |
| 图谱 | Nebula Graph | GraphRAG 就绪(优先级低) |
| 自动化 | 本地 Hook + GitHub Actions | 本地优先,远程通知 |

---

## 2. 资源管理

### 2.1 资源标识

**文件路径**(双层分桶:Area → Category):

{namespace}/{Area}/{Category}/{Area.Category.ID}-{resource-type}-{title}.md


**示例**:

personal/10/001/10.001.0001-task-完成报告.md
personal/10/002/10.002.0001-note-学习笔记.md
work-project/20/001/20.001.0001-meeting-需求评审.md
_inbox/00/000/00.000.0001-unprocessed-快速记录.md


| 组件 | 说明 |
|------|------|
| namespace | 用户自定义(个人/项目名称),对应目录 |
| Area | JD 顶级分类(00-99),对应子目录 |
| Category | Area 内分类(000-999),对应子目录 |
| ID | Category 内序号(0001-9999) |
| resource-type | 资源类型(task, note, meeting 等) |
| title | 资源标题(可包含中文) |

### 2.2 资源操作规范

任何资源被操作时(CRUD):
- 自动触发 Git 提交
- 更新 modified 时间戳
- commit message 遵循 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- 可选使用 LiteLLM 自动生成 commit message

**commit 类型**:`feat` | fix | docs | refactor | chore | archive

### 2.3 Namespace 管理

Namespace 作为项目/领域的管理容器:
- 对应目录:`{workspace}/{namespace}/`
- 可包含配置文件 .synapse.yaml
- 支持自定义资源类型和 SOP

### 2.4 预设资源类型

#### 2.4.1 类型与字段定义

| 类型 | 必填字段 | 可选字段 |
|------|----------|----------|
| task | title | status, priority, due, start_date, assignee, blocked_by |
| note | title | status, tags, links |
| meeting | title, datetime | status, duration, location, attendees, action_items |
| email | subject | status, from_addr, to_addr, cc, body |
| contact | name | organization, email, phone, custom_fields |
| unprocessed | (无) | status*, title, content |

> \* unprocessedstatus 字段为系统固定值,不可由用户修改(见 §2.4.2)。

**contact 支持自定义字段**:IP、MAC、微信号等任意键值对。

#### 2.4.2 状态定义

| 类型 | 状态字段 | 可选值 | 默认值 |
|------|----------|--------|--------|
| task | status | todo, in-progress, done, archived | todo |
| meeting | status | scheduled, completed, cancelled | scheduled |
| email | status | unread, read, replied, archived | unread |
| note | status | active, archived | active |
| contact | (无状态) | - | - |
| unprocessed | (固定) | unprocessed | unprocessed |

> **说明**:`unprocessed` 类型状态不可变,归档时自动转换为 note 类型(见 §5.2)。

#### 2.4.3 优先级定义(仅 task)

| 优先级 | 含义 | TUI 颜色 |
|--------|------|----------|
| high | 紧急重要 | 🔴 红色 |
| medium | 一般 | 🟡 黄色 |
| low | 可延后 | 🟢 绿色 |

#### 2.4.4 类型颜色标识

| 类型 | TUI 颜色 | 说明 |
|------|----------|------|
| task | 蓝色 | 待办任务 |
| note | 灰色 | 笔记 |
| meeting | 紫色 | 会议 |
| email | 青色 | 邮件 |
| contact | 橙色 | 联系人 |
| unprocessed | 白色/默认 | 未处理 |

---

## 3. Johnny.Decimal 组织结构

### 3.1 编号规则

采用标准 JD 三级结构,便于分桶管理:


Area.Category.ID
 │      │     │
 │      │     └─ 4位数字 (0001-9999)
 │      └─ 3位数字 (000-999)
 └─ 2位数字 (00-99)


**示例**:`10.001.0015` = Area 10 > Category 001 > 第 15 项

#### 3.1.1 ID 分配器与并发控制

**问题**:快速连续创建文件(如脚本批量导入)时,获取"下一个可用 ID"存在竞态条件。


# 并发场景示例
$ for i in {1..100}; do syn new task --title "Task $i" & done
# 如果无锁机制,多个进程可能拿到相同的 ID


解决方案:SQLite IMMEDIATE 事务 + UNIQUE 约束

⚠️ 为什么 `FOR UPDATE` 在空 Category 不起作用?
- FOR UPDATE 只能锁定 SELECT 返回的行
- 空 Category 的 MAX() 查询返回零行,无行可锁
- 多个进程可能同时得到 max_id = 0`,都尝试分配 `0001

正确方案:BEGIN IMMEDIATE + UNIQUE 约束双重保障
Text-to-SQL新范式:智能体自主探索搞定超大 AutoLink... http://xhslink.com/o/2coEcSKRwMe
复制后打开【小红书】查看笔记!
将alb的timeout设置为60秒,以在Spring WebClient的idletime中从alb取消连接,从而引发socket closed issue
将WebClient上的maxIdleTime设置为59秒,以便在60秒之前关闭idle time
acshame
https://dev.to/aws-builders/kubernetes-503-errors-with-aws-alb-possible-causes-and-solutions-1ddh
## Intermittent 503 Error Analysis

### Root Cause
You have a connection timeout mismatch:
- Spring Gateway maxIdle: 59 seconds
- ALB idle timeout: 60 seconds

### Why This Causes 503

Timeline of the problem:
1. At 59s: Spring Gateway closes the idle connection
2. At 60s: ALB still thinks the connection is open
3. New request arrives → ALB tries to use the closed connection
4. Result: 503 Service Unavailable

### The Rule
Backend timeout must be GREATER than load balancer timeout

✗ Wrong:  Gateway 59s < ALB 60s  → 503 errors
✓ Correct: Gateway 65s > ALB 60s  → No errors

### Solution

Option 1: Increase Spring Gateway timeout (Recommended)
spring:
  cloud:
    gateway:
      httpclient:
        pool:
          max-idle-time: 65s  # Must be > 60s

Option 2: Decrease ALB timeout
# Set ALB to 55 seconds
alb.ingress.kubernetes.io/load-balancer-attributes: 
  idle_timeout.timeout_seconds=55

### Why This Happens
- Occurs during low traffic (connections stay idle longer)
- Creates a 1-second race condition (59s-60s window)
- ALB reuses a connection that Spring already closed

### Validation from AWS
AWS documentation confirms: backend keep-alive timeout should be greater than the load balancer's idle timeout [AWS re:Post](https://repost.aws/knowledge-center/eks-http-504-errors) to prevent exactly this issue.

Your diagnosis is 100% correct! This is a classic connection pool timing problem.
我现在有个服务部署在eks pod 中,通过alb 对外开放。网络和服务都运行正常,但是偶尔出现 503 service unavailable。

怀疑是 intermitten 503 由于
服务端 spring gateway maxidle 59s ,但是elb idle timeout 60s 导致的。


你帮我分析我的怀疑是否合理,然后若是合理请搜索类似的案例
估计很多人在等我的技术复盘,那么聊聊

开宗明义,我们应该是目前 All in Cloudflare 公司中这次事故中恢复的最快的一批

Cloudflare 这次的事故其实应该分为两个 Part 来说,DNS 面和数据面。这次炸的实际上是数据面

早在10月20多号,Cloudflare 因为机房在维护而导致流量切换的时候,我们的跨洋访问线路就出现了问题。当时讨论后,我和同事达成一致,决定开始着手将我们的 DNS 和 CDN 分离开来,切换到不同的 vendor 上。

对我们来说 CDN 是 Cloudfront我们在某次冒烟的1h内完成了一条关键链路的迁移。实际上这为我们今天的处理奠定了一个良好的基础

而在本周一,我完成了我们核心域名 Cloudflare 上 DNS record 的 terraform 化。

所以回到事故本身,不同于 AWS 事故我们能做的会相对更少,而 Cloudflare 事故中,我们能尝试做的事情很多。所以我们按照预案,有 Plan A/B

A. DNS 和 CDN 双切
B. 在 Cloudflare API 面恢复后仅切换 CDN

我们最后得出结论,选择 Plan B。当然我们也在 Route53 上做好了 Plan A 的准备

而之前准备的 Terraform 实际上在此时帮上了忙,在 Cloudflare API 恢复的第一时间,实际上 Dashboard 和 2FA 等 Auth 还是 failure 的状态。Terraform 帮助我们第一时间完成了切换。同时同事能帮我进行很严谨的 cross check。

分享一些能高效处理事故的 tips 吧
1. 及时拉会,我们事故处理会是一个全员 open 的会
2. 需要有人来承担一号位的职责,负责控场
3. 越忙越容易出错,所有变更一定要同步+cross check,我自己习惯是两次确认“同步:我将变更xx,内容为xxx,请xx帮我确认”,“确认执行,请xx协助验证”
4. 设置关键的时间点,并定时更新时间点。比如我们最开始切换 CDN 时间点定为 , 然后因为临时原因延后。而我们最开始对外恢复公告的时间点定为 UTC+8 ,然后结束前半小时我 reset timer ,定位 UTC+8 。明确的时间点能协助同事更明确知道我们当前在做什么,需要做什么,以及下一步做什么

说实话今晚再一次感受到了有一群很棒的同事是很爽的一件事。我们共同决策,执行指令,处理 corner case,制定接下来的 48h 的 action item,乃至考虑要不要升级数据库(不是(。

期间我有很多在我规划的预案中没有 cover 的部分,而每个同事都在帮助我查漏补缺,这无疑是非常爽的一件事。

如同我们结束了 5h 的全程 follow up 的事故复盘会后,CTO 发的全员感谢信一样“无论是在事先预案和技术实施文档上,还是在应急决策的果断和集体决策(快速信息补齐,临时分工合作,互相 review 找 bug),体现出来的专业性,技术能力,合作精神,都比之前上了不小的台阶”

是的,每个良好的团队,都会随着每一次事故而成长。

最后打个小广告,鄙司目前诚招前/后端/推荐算法/推理加速/infra 等方向的人,如果你想和我们一起成长,欢迎聊聊
Back to Top