mcpField
M
migrating-nango-deletion-detection

migrating-nango-deletion-detection

github.com/nangohq开发3124 次安装10 周前更新
代码仓库

关于 migrating-nango-deletion-detection

用于将 Nango 同步流程迁移到新的删除检测机制的技能,面向维护同步任务的开发者。它说明删除跟踪的调用顺序,并为跨执行窗口的完整刷新补充检查点处理。

主要功能

  1. 01替换旧删除检测调用
  2. 02按顺序开始和结束删除跟踪
  3. 03为分页刷新恢复检查点
  4. 04逐页保存并清除检查点
  5. 05提供测试与模拟数据命令

适用场景

  1. 01迁移 Nango 同步任务的删除检测
  2. 02为耗时的完整刷新续接分页
  3. 03避免数据未完整获取时误删记录

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nangohq/skills --skill migrating-nango-deletion-detection

安装后在 Claude Code 中输入/migrating-nango-deletion-detection确认已加载。

详细介绍

迁移 Nango 删除检测

操作步骤

  1. 查找旧用法:
    • deleteRecordsFromPreviousExecutions(
    • trackDeletes: / track_deletes
  2. 对每个需要自动检测删除的同步任务和模型:
    • 在 exec 开始处(获取/保存数据之前)添加 await nango.trackDeletesStart('ModelName')。
    • 将 await nango.deleteRecordsFromPreviousExecutions('ModelName') 替换为 await nango.trackDeletesEnd('ModelName')。
    • 将 trackDeletesEnd 放在所有 batchSave/batchUpdate/batchDelete 调用之后。
  3. 安全性:
    • 只有在 trackDeletesStart 和 trackDeletesEnd 之间已获取并保存完整数据集时,才能调用 trackDeletesEnd(否则可能导致误删)。
    • 尽量让异常向外传播。如果使用 catch,则在数据不完整时重新抛出异常。

分多次执行的完整刷新

完整刷新同步任务除了删除跟踪外,还需要分页 checkpoint(页码/游标/偏移量)。Nango 同步任务在有时间限制的执行窗口中运行;如果没有 checkpoint,未能在该窗口内完成的任务下次会从第 1 页重新开始,浪费计算资源重复获取前面的页面,却始终无法处理数据集的其余部分。

  • 先读取 checkpoint(await nango.getCheckpoint()),如果存在,则从该位置恢复分页。
  • 在刷新窗口内的每次执行开始时调用 trackDeletesStart('ModelName')。重复调用是安全的——它不会覆盖同一逻辑刷新中先前执行已开启的删除跟踪窗口的起点。
  • 每次成功调用 batchSave() 后,都使用下一个页码/游标调用 saveCheckpoint()——每一页都要调用,包括最后一页。不要使用“仍有更多页面”作为调用条件(if (nextPage) { ... });如果整个数据集只需第一页就能处理完,任务就不会保存 checkpoint。
  • 仅在保存最后一页后调用 clearCheckpoint()。由于每个已处理的页面都必须调用 saveCheckpoint(),常规页面处理路径会有 checkpoint 行可供清除。如果某条独立路径完全没有创建 checkpoint(例如,该路径没有处理任何页面),则不要在该路径调用 clearCheckpoint();运行时会抛出 checkpoint_conflict。这不能代替保存最后一页。
  • 仅在调用 clearCheckpoint() 之后调用 trackDeletesEnd('ModelName')——也就是说,只有在完成整个数据集的保存的那次执行中才调用。

测试

  • 代码更改后重新录制 mock:
    • nango dryrun <sync-name> <connection-id> --validate -e dev --no-interactive --auto-confirm
    • nango dryrun <sync-name> <connection-id> --save -e dev --no-interactive --auto-confirm
    • nango generate:tests && npm test
  • 切勿手动编辑 *.test.json。

前后对比

// Before
for await (const page of nango.paginate(cfg)) {
    await nango.batchSave(page, 'Ticket');
}
await nango.deleteRecordsFromPreviousExecutions('Ticket');
// After
await nango.trackDeletesStart('Ticket');

for await (const page of nango.paginate(cfg)) {
    await nango.batchSave(page, 'Ticket');
}

await nango.trackDeletesEnd('Ticket');

如果同步任务可能超出执行窗口(数据集较大、服务提供方较慢),请添加分页 checkpoint,以便 trackDeletesStart/trackDeletesEnd 在多次执行中仅包围同一次逻辑刷新:

// After (checkpointed, multi-execution safe)
const checkpoint = await nango.getCheckpoint<{ page?: number }>();
let page = checkpoint?.page ?? 1;

// Safe on every execution: does not overwrite an already-open window.
await nango.trackDeletesStart('Ticket');

for await (const results of nango.paginate({
    ...cfg,
    paginate: {
        ...cfg.paginate,
        offset_start_value: page,
        on_page: async ({ nextPageParam }) => {
            page = typeof nextPageParam === 'number' ? nextPageParam : undefined;
        }
    }
})) {
    await nango.batchSave(results, 'Ticket');

    // Save on every page, including the last — do not guard this with
    // `if (page !== undefined)`. Skipping it whenever there is no next page
    // means a run whose entire dataset fits on the first page never saves a
    // checkpoint, and the clearCheckpoint() below would then fail with
    // checkpoint_conflict (deleting a row that was never written).
    await nango.saveCheckpoint({ page });
}

// Every page, including the last, was checkpointed.
await nango.clearCheckpoint();
await nango.trackDeletesEnd('Ticket');

评论

支持 Markdown