恢复意外删除的工单

CloudflareBeginner
立即练习

介绍

由于一次意外的 SQL 删除操作,一条工单消失了,但应用配置仍然正确。你将保存 D1 Time Travel 书签,使用一条合成记录重现数据丢失,然后在保留未受影响工单的同时恢复同一个数据库。

本次独立恢复演练使用一个一次性的远程数据库和一个已提供的只读 Worker。你将在恢复前验证缺失状态,并在恢复后验证应用访问。

使用你自己的学习账号和一台全新的 VM。设置过程会先准备 Node.js 22.22.0,然后在 /home/labex/project/ticket-database 下运行 npm install,安装项目本地的 Wrangler 4.131.1 以及评估所需的依赖。直接依赖的版本已固定;安装过程会创建自己的锁定文件。设置过程中不会登录云端,也不会执行评估数据库操作。在个人计算机上操作时,请在项目中运行 npm install --save-dev wrangler@4.131.1,安装相同版本的 Wrangler。

本实验使用 D1 免费额度范围内的少量合成记录。现有账号的用量也会计入这些额度。你不需要购买域名。在确认资源已删除并完成注销之前,请保留这台 VM。

为这台 VM 授权并选择账号

在本步骤中,你要将这个全新的终端连接到自己的学习账号。仅登录 Dashboard 不会为这台 VM 授权。D1 权限用于创建、修改和删除数据库;Workers 权限用于部署;KV 权限用于支持 Wrangler 的清理资源清单。授权前请查看实际的授权页面,包括 Background Access。

打开已准备好的项目并检查固定的 CLI 版本:

cd /home/labex/project/ticket-database
npx wrangler --version

预期输出为 4.131.1。启动设备授权;--device 会显示浏览器验证码,--browser=false 会让你自行决定是否打开浏览器:

npx wrangler login --device --browser=false --scopes account:read user:read d1:write workers_scripts:write workers_kv:write

在浏览器中打开显示的 URL,输入当前验证码,确认你的学习账号和权限,然后完成授权。等待终端确认成功。不要将密码或令牌粘贴到项目文件中。

npx wrangler whoami --json

检查 loggedIn: true,然后读取账号的 nameid,即使列表中只有一个账号也要读取。将目标账号的 ID 复制到下面的配置中。下面的 Shell 变量使用 6 个随机字节(12 个十六进制字符),避免与其他学习者的资源名称冲突。Here-document 会将 JSON 两行之间的内容写入 JSON 文件;其中的 $RUN 会展开。

$schema 前的反斜杠会保留这个 JSON 键的原样;$RUN 仍会展开为本次运行的唯一名称。

RUN=labex-c04-d07-$(openssl rand -hex 6)
cat > wrangler.jsonc <<JSON
{
  "\$schema": "./node_modules/wrangler/config-schema.json",
  "name": "$RUN",
  "account_id": "YOUR_ACCOUNT_ID",
  "main": "src/index.js",
  "compatibility_date": "2026-09-15",
  "workers_dev": true,
  "preview_urls": false
}
JSON

运行这段命令前,先将 YOUR_ACCOUNT_ID 替换为实际账号 ID。保持此终端打开,以便 RUN 变量继续可用。name 用于标识本次运行;account_id 用于指定云端操作所使用的账号。该文件是普通 JSON,同时也是有效的 JSONC。写入该文件不会部署 Worker。

建立已知可用的恢复点

在本步骤中,你要创建一次性数据库和已提供的只读工单 API。Time Travel 会在原位置恢复数据库的较早状态。它不会创建替代数据库,并且可能覆盖所选时间点之后的更改。本实验只在刚创建的实验资源上使用它。

创建一次性的云端数据库。--binding DB 为应用代码提供简短名称,--update-config 会将数据库的实际名称和 UUID 写入 wrangler.jsonc--use-remote=false 会保持开发环境使用本地数据库:

npx wrangler d1 create "$RUN-db" --binding DB --update-config --use-remote=false

读取创建出的名称和 ID,然后检查已保存的绑定:

cat wrangler.jsonc

DB 条目必须指向本次运行创建的数据库。绑定是代码与资源之间经过配置的连接。绑定中的 UUID 用于标识云端数据库,而 --local 使用的是这台 VM 中独立的 SQLite 数据库。运行 SQL 命令时,始终明确指定 --local--remote

npx wrangler d1 execute DB --remote --file schema.sql
npx wrangler deploy

复制部署后的 URL,然后读取两条合成工单:

URL='YOUR_DEPLOYED_HTTPS_URL'
curl -i "$URL/tickets/1"
curl -i "$URL/tickets/2"

预期工单 1 返回 200(Cannot sign in,状态为 open),工单 2 返回 200(Invoice copy,状态为 closed)。如果部署仍在传播,请在最多一分钟内重复读取,直到 HTTP 状态和 JSON 内容一致。

检查数据库信息,然后将当前书签保存为恢复文件。书签是不透明的数据库历史位置。使用 > 重定向可以将 JSON 响应写入指定文件:

npx wrangler d1 info DB
npx wrangler d1 time-travel info DB --json > recovery.json
cat recovery.json

确认数据库使用生产后端,并且 recovery.json 中的 bookmark 非空。在整个实验过程中保持此文件不变。生产环境中的 D1 始终启用 Time Travel;Free 计划保留 7 天,Paid 计划保留 30 天。本次会话内的恢复只需要几分钟的历史记录。CLI 帮助信息中提到的 30 天不会覆盖你当前套餐的保留期限。

重现一次范围受控的意外删除

在本步骤中,你只从本实验数据库中删除合成工单 1,并证明应用出现相应症状。先检查 wrangler.jsonc,确认 DB 与刚创建的数据库名称和 UUID 匹配。不要对任何现有应用数据库运行这些命令。

cat wrangler.jsonc
npx wrangler d1 execute DB --remote --command "DELETE FROM tickets WHERE id = 1;"

读取 API 和未受影响的记录:

curl -i "$URL/tickets/1"
curl -i "$URL/tickets/2"
npx wrangler d1 execute DB --remote --command "SELECT id, subject, status, source FROM tickets ORDER BY id;"

工单 1 必须返回 404,并包含 {"error":"not_found"}。工单 2 仍然返回原来的 200 响应;SQL 查询结果中只能包含工单 2。网络故障或平台返回的 404 页面,不能证明删除操作已经发生。

在恢复前完成本步骤的验证。该验证会检查数据库中确实缺少对应记录;如果未先观察故障就恢复,会跳过这次事件的证据。

恢复历史并验证应用访问

在本步骤中,你要将同一个数据库恢复到已保存的书签位置。读取 recovery.json,将准确的 bookmark 字符串复制到 BOOKMARK,然后再次检查已配置的数据库身份:

cat recovery.json
BOOKMARK='YOUR_SAVED_BOOKMARK'
cat wrangler.jsonc
npx wrangler d1 time-travel restore DB --bookmark "$BOOKMARK"

该命令会警告你:恢复操作将覆盖数据,并取消正在执行的查询。只确认这个一次性数据库。预期会看到恢复成功消息和一个用于撤销的书签。不要重新创建数据库、重新导入架构或插入缺失记录:这些操作会绕过本次要练习的恢复技术。

查询恢复后的数据库及其现有应用绑定:

npx wrangler d1 execute DB --remote --command "SELECT id, subject, status, source FROM tickets ORDER BY id;"
curl -i "$URL/tickets/1"
curl -i "$URL/tickets/2"

原来的两条记录和对应的 API 响应都必须恢复。Worker 仍然指向同一个 UUID,不需要替换绑定。如果恢复期间读取暂时不可用,请重复读取;不要悄悄地用新的种子数据替代恢复操作。

在 Dashboard 中打开准确的 D1 数据库,确认其 ID 未发生变化,然后使用只读视图检查已恢复的工单。此检查点用于将恢复的数据与资源对应起来;SQL/API 结果是功能验证证据。在账号的 Audit Logs 中,将 Resource ID 筛选为此数据库 UUID,并选择覆盖恢复时间的范围。点击事件时间打开详情,再展开 Resource,检查 type: database.time_travel.restore。确认资源 ID 和成功状态与恢复命令输出一致。审计记录可能需要一段时间才会出现;列表暂时为空不代表操作失败。数据检查证明状态已恢复,而实际的恢复输出和审计事件则记录了恢复操作本身。

同一 D1 数据库中恢复的工单

此示例显示同一数据库在恢复后的两条原始工单。生成的名称标识本次示例运行,你的名称和 UUID 会不同。截图展示恢复后的数据行。SQL/API 检查验证访问已恢复,而实际 Time Travel 命令输出和匹配的审计事件确认所执行的恢复操作。

Time Travel 审计事件

事件标题使用通用操作 create。展开的 Resource 区域中,type: database.time_travel.restore 标识恢复操作。请核对成功状态、准确的数据库 UUID 和时间;此处数值属于本次示例运行。

删除一次性资源

在本步骤中,在 VM 仍处于授权状态时,只删除本实验创建的资源。先完成所有功能检查。在确认删除完成之前,保留配置文件。

npx wrangler delete

确认删除的只有本次运行配置中的 Worker 名称。

npx wrangler d1 delete DB

检查提示信息,确认删除的只有本次运行创建的数据库。然后列出数据库:

npx wrangler d1 list --json

在成功响应中,之前记录的数据库名称和 UUID 必须不存在。其他资源可能仍然保留。身份验证错误或网络错误不能作为结论:请先恢复访问权限,然后重新读取,再继续操作。在仍处于登录状态时完成本步骤的验证。

结束这台 VM 的授权

在独立的删除检查通过后,再执行本步骤结束授权。注销会删除 Wrangler 在这台 VM 上保存的授权信息;仅关闭 VM 并不会清理云端资源。

npx wrangler logout
npx wrangler whoami --json

预期输出为 loggedIn: false。未认证的查询可能以非零状态退出;只有当结构化响应明确表示你已注销时,这才是预期行为。完成验证后,关闭实验环境。

总结

你练习了如何恢复意外删除的工单。你检查了可观察的数据库结果,明确保留了所选账号和本地状态,并在注销前删除了一次性资源。