# 生命周期与查重 (/zh/docs/guides/lifecycle)

有效期的三层取值与访问续期、到期清理与三段式删除、冷图待清理的打标与裁决，以及精确重复自动合并与相似重复人工裁决。

## 有效期（TTL） [#有效期ttl]

每张图可以有一个有效期，到期后自动删除。有效期按三层取值，从上往下第一个有定义的生效：

| 层级 | 在哪设置 | 取值 |
|---|---|---|
| 单次上传 | 表单字段 `ttl`、URL 转存的 JSON 字段 `ttl`、后台上传弹窗的「有效期」 | 秒数；`0` 或 `never` 表示永久 |
| 用户默认 | 「用户」页 → 编辑 →「默认有效期（小时）」 | 留空表示随全局默认；`0` 表示永久；正数为小时数 |
| 全局默认 | 「设置 → 运行配置」的「默认有效期」`default_ttl_hours` | `0` 表示永久（出厂值）；正数为小时数 |

- 单次上传显式写 `0` 或 `never`，会覆盖用户默认与全局默认，这张图就是永久的。
- S3 上传不能逐次指定，只按用户默认与全局默认取值。
- 到期时刻在上传时算定并保存。之后再改用户默认或全局默认，不影响已有的图。
- 要表达「临时」，给图设一个短有效期即可；没有单独的临时目录或临时上传类型。
- 单次上传、用户默认与全局默认的上限都是 876000 小时（100 年），超出即拒绝。其余换算成时长的运营配置（扫描间隔、删除宽限、保留期、超时等）按各自单位折算，同样以 100 年为上限。

已有图片的有效期在图片详情里修改（图片的归属用户与管理员都可以）：

- 「修改有效期」→ 填天数后点「延长」：到期时刻改为从现在起算的 N 天后，这个时长也成为该图新的有效期（访问续期按它顺延）。
- 「设为永久」：去掉到期时刻。

## 访问即续期 [#访问即续期]

「访问即续期」`ttl_renew_on_access` 出厂开启。开启时，带有效期的图每被公开访问一次，到期时刻就顺延为「这次访问被记录的时刻 + 它的有效期」。
效果是有效期变成「连续这么久没人访问才过期」：有人在用的图一直保留，没人看的图到期清理。关闭后，到期时刻固定不变。

- 访问在内存里累计，每 `activity_flush_seconds`（出厂 60 秒）批量写入一次，续期在写入时发生。写入那一刻已经到期的图不再续期：到期是终态。
- 只有 `/i/` 与 `/o/` 的公开访问算数；后台缩略图与预览、S3 GetObject 不算，见 [后台浏览不计访问](./access.mdx#console-browsing)。
- 永久的图不受影响。

## 到期清理 [#到期清理]

清理扫描在进程启动时先跑一轮，之后每 `cleanup_sweep_seconds`（出厂 60 秒）一轮，每轮依次：

1. 删除已到期的图（每轮最多 500 张，积压的下一轮继续）；
2. 物理删除已过宽限期的文件（见下节）；
3. 给冷图打待清理标记（见 [冷图待清理](#冷图待清理)）；
4. 回收超过保留期的上传幂等键；
5. 设置了保留天数时，回收过期的审计日志（`audit_retention_days`，出厂 0 表示永久保留）。

图一到期，对外链接就返回 404，也不会再被访问续期；记录与文件由之后的清理扫描回收。在那之前，后台「图片」页里它显示为「已过期」，仍可手动删除。进程停机期间到期的图，在重启后的扫描里补删。

## 删除流程 [#删除流程]

所有删除都走同一条流程：到期、后台删除（单张或批量，一次最多 100 张）、待清理裁决的删除、S3 DeleteObject。

<Steps>
<Step>

### 删除引用 [#删除引用]

在一个事务里删除这条图片记录（连同指向它的幂等键），并把它所指物理文件的引用计数减 1。链接立即返回 404。
配置了 Cloudflare 缓存清理时，同时为 `/i/<短ID>` 及这张图生成过的衍生图参数组合排队清理 CDN 缓存；`/o/` 别名链接不在清理范围内。见 [CDN](../operations/cdn.mdx)。

</Step>
<Step>

### 标记待删 [#标记待删]

引用计数降到 0 时，物理文件被标记为待删除，删除时刻 = 现在 + 删除宽限 `delete_grace_minutes`（出厂 0，即下一轮扫描就删）。

</Step>
<Step>

### 物理删除 [#物理删除]

删除时刻过后的那一轮扫描里：先删掉它的衍生图缓存，再在事务内复查它确实无人引用后删除数据库记录，然后为每个持有副本的渠道排队删除对象。
渠道删除异步执行、失败重试；最终没删掉的对象成为孤儿，由对账任务回收。

</Step>
</Steps>

**引用计数**：一个物理文件可以被多条图片记录共享（查重合并的结果）。删除其中一条不影响其他记录，只有最后一条引用删除后物理文件才会进入删除流程。图片详情里的「引用数」显示当前值。

后台的删除确认框会按当前宽限期提示物理文件大约多久后清理。删除用户之前必须先删掉该用户名下的全部图片。

## 冷图待清理 [#冷图待清理]

长时间没人访问的图会被打上「待清理」标记，进入后台「待清理」页等管理员裁决。**不会自动删除。**
删除不可撤销，所以机器只负责发现，删不删由人决定；相似重复的合并也是同一原则。

- 阈值是「冷图清理阈值」`cold_cleanup_days`，出厂 90 天；设为 0 不再打标。
- 打标：每轮清理扫描时，最近一次公开访问（从未访问过则取上传时间）早于阈值、且未被豁免的图，打上标记。
- 摘标：
  - 这张图被公开访问（在下一次访问计数写入时摘掉）；
  - 管理员裁决「保留」；
  - 管理员取消该图的清理豁免（下一轮扫描重新判定）；
  - 这张图被删除。
- 调大阈值或把阈值设为 0，不会摘掉已有的标记。
- 冷图判定与有效期互不相关：带有效期的图同样可能被标记，被豁免的图照样会到期。

### 裁决 [#裁决]

「待清理」页（仅管理员）按最近访问时间从早到晚列出，可单张或批量操作：

- 「保留」：给图设上清理豁免，之后不再参与冷图打标，有效期与访问续期不受影响。可在图片详情里取消豁免。
- 「删除」：走上面的删除流程。

清理豁免只有管理员能设置，与冷图裁决同属管理员的权限，归属用户无法自己给图打上豁免、绕开回收：图片详情里的「清理豁免」开关可以在图变冷之前预先打开；普通用户看得到状态但不能修改。
「图片」页的筛选「仅看已豁免」列出全部已豁免的图。

## 查重 [#deduplication]

查重不在上传路径上进行，上传不会因此变慢。后台查重循环在进程启动时先跑一轮，之后每 `dedup_scan_seconds`（出厂 300 秒）一轮，每轮先合并精确重复，再扫描相似重复。

### 精确重复：自动合并 [#精确重复自动合并]

实际保存的字节完全相同（SHA-256 相同）的物理文件，合并没有任何风险，自动进行：

- 保留其中最早的一份，其余文件的图片记录改为指向它，引用计数并入；
- 多出来的文件标记待删，按删除宽限期物理删除；
- 跨用户同样合并。每条图片记录仍保留自己的短 ID、归属用户、有效期与访问计数，所有链接继续可用；
- 配额按引用计全额，合并不减少任何用户的已用量。

### 相似重复：人工裁决 [#相似重复人工裁决]

每个物理文件上传时都算了 64 位感知哈希（pHash）。两个文件的哈希差异位数（汉明距离）不超过「相似判定阈值」`dedup_phash_max_distance`（出厂 10）时，作为一对候选进入「疑似重复」页。

- 阈值越大越宽松，误报越多；设为 0 不做相似扫描。后台提示距离 0–2 基本是同一张图。
- 距离为 0 也只进候选、不自动合并：感知哈希相同不代表字节相同。
- 扫描是增量的：每轮只拿新文件与已有文件比较，在内存里逐一计算距离，自部署的规模不需要索引结构；进程重启后会全量重扫一次，已忽略的候选不会再出现。

### 裁决与选择保留哪一张 [#裁决与选择保留哪一张]

「疑似重复」页（仅管理员）把每对候选并排显示为左图、右图，附格式、尺寸、大小、引用数与距离，按距离从小到大排列：

- 「保留这张」→ 确认「合并」：另一张的全部引用改为指向保留的这张，被合并的文件按宽限期清理，涉及它的其他候选一并移除。**不可撤销。**
- 「忽略」：这一对以后不再提示，可批量忽略。

合并后，被合并一方的所有链接（包括其他用户的引用）开始输出保留方的内容：尺寸、格式、画面可能都不同。所以通常保留分辨率更高、格式更合适的一张；两张实为不同图片时选「忽略」。
已经缓存了旧内容的浏览器与 CDN 在缓存过期前仍显示旧图。

合并与忽略都记入审计日志（动作「合并重复图」「忽略重复图」）。

## 相关配置 [#相关配置]

| 配置键 | 后台名称 | 出厂值 |
|---|---|---|
| `default_ttl_hours` | 默认有效期 | 0（永久）|
| `ttl_renew_on_access` | 访问即续期 | 开 |
| `cold_cleanup_days` | 冷图清理阈值 | 90 天 |
| `delete_grace_minutes` | 删除宽限 | 0 分钟 |
| `cleanup_sweep_seconds` | 清理扫描间隔 | 60 秒 |
| `activity_flush_seconds` | 活跃度落库间隔 | 60 秒 |
| `idempotency_key_ttl_hours` | 幂等键保留期 | 24 小时 |
| `dedup_scan_seconds` | 查重扫描间隔 | 300 秒 |
| `dedup_phash_max_distance` | 相似判定阈值 | 10 |
| `audit_retention_days` | 审计日志保留天数 | 0（永久）|

都在「设置 → 运行配置」修改，保存即生效，见 [配置](../configuration.mdx)。
