Skip to content

加载期间的自动化

另有 19 种语言版本

English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · ไทย · Українська · Español (México) · Français (Canada) · Deutsch (Schweiz)

In a plant room, the valves beside a pump stand closed and its cover is off, while a bypass pipe with an open valve carries the flow around it.
图片由 AI 生成

第 3 个模块,共 5 个,属于 Data Architect 课程第 10 章迁移与同步。每个模块都可以单独阅读。 上一篇:大数据量加载 · 下一篇:切换周末

**本模块回答的问题:**在加载迁移数据期间,Salesforce 的自动化应该怎么处理?

RouteDesk’s records are ready: about 707,000 of them, prepared, sorted by parent, rehearsed. You start the load, and Salesforce starts doing exactly what you configured it to do. Flows fire, triggers run, validation rules evaluate, emails send, tasks get created, rollups calculate, integrations launch, events publish. Your 707,000-record migration isn’t performing 707,000 operations anymore. It’s performing 707,000 records multiplied by everything each record causes. That’s a different migration. ⟲

Here’s the landscape again, the weekend RouteDesk retires. The migration arrow is amber. Now look at what else leaves Salesforce when a Work Order is created or changes status. ⟲

The arrows a load sets off Steve Trucking's landscape from Checkpoint 1, in the same places, the weekend RouteDesk retires. The migration arrow from RouteDesk into Salesforce is in amber. Three arrows leaving Salesforce are red with an X, because normal automation would fire them for every migrated Work Order: status events to the integration layer, delivery counts to the integration layer, and the day-before texts to the SMS and email provider. Underneath: load 196,400 Work Orders with the automation on, and three more arrows fire for every one of them: status events, delivery counts and day-before texts. {"author": "Steve Simpson", "blueprint": "1.0.1", "builder": "standard 1.54.0", "built": "2026-10-30", "id": "DGM-DA-MG-30", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "system-landscape 0.13.0", "theme": "stevetecharc 1.4.0"} ABOVE: IDENTITY, APPEXCHANGE, WEB PEOPLE RIGHT: INTERNAL SYSTEMS BELOW: CUSTOMER CHANNELS BOTTOM RIGHT: PARTNERS AND PROVIDERS Dispatch coordinators 45, inside 9 partner DCs Delivery crews ~700 on 330 trucks Care and office staff 100: service, ops, finance Retail Partner users ~300 at 3 partners Recipients ~1 million a year Corporate IdP SSO for office staff only Retail Partner portal Tracking page INTEGRATION Snowflake status history, analytics FleetLink raw GPS stays here Finance ERP invoices partners, pays crews Photo storage 4–5 million a year, off core RouteDesk retiring: 8 years, ~5 million deliveries Phone care agents Email email-to-case SMS and email provider day-before message, with a link Redrock REST API, webhooks Keystone CSV over SFTP Brightwave EDI through a third-party network Salesforce Field Service, one US org a link, no login office staff only calls cases in manifests in status out manifests in status out manifests in status out upserts, partner key status events status events latest position only delivery counts delivery counts photos, from the crews' app day-before, with a link what's still open: migrated once Salesforce a community people identity, apps, web an internal system a customer channel the integration layer starts at the system that opens the connection; the label says what moves red with an X: fires for every migrated record unless you decide otherwise a shared certificate: trust, no direct call the migration Load 196,400 Work Orders with the automation on, and three more arrows fire for every one of them: status events, delivery counts and day-before texts. © 2026 Twinshark LLC · stevetecharc.com
点击放大

One arrow in. Three more arrows out, for every record, unless we decide otherwise. ⟲

Every one of those arrows was designed in chapter 9 for a delivery that just happened: a status changed, so tell the partner and Snowflake; a delivery finished, so count it for invoicing; a delivery is tomorrow, so text the Recipient. The load creates 196,400 Work Orders in one weekend, and about 190,000 of them arrive already completed. To the automation, each one looks like a delivery that just happened. ⟲

Salesforce sees a record transaction. It doesn’t know “this is historical data loaded during a controlled cutover.” A flow sees a new Account and does what it was built to do: creates an onboarding task, sends a welcome email, publishes an event, updates a related record, calls another system. Correct when a sales rep creates one account on Tuesday afternoon. Completely wrong when a migration creates 800,000 historical accounts on Saturday night. Same operation, different business context. At Steve Trucking, a Work Order arriving with a status of Completed looks exactly like a crew finishing a delivery five minutes ago. ⟲

所以对于一次大型迁移,我的出发点是:正常的业务自动化**不应该盲目地针对加载运行。**这不是说“关掉一切”。而是说每一个重要的自动化都要有一个有意识的决定,而我不想等到生产环境发出了 400,000 封邮件才发现答案。

三种选择:不需要它、模拟它、推迟它

Section titled “三种选择:不需要它、模拟它、推迟它 ”

For each automation, I ask what it does and what happens if it doesn’t run, and then I put it in one of three categories. ⟲

**不需要它(消除)。**对于迁移过来的记录,这个行为就不应该发生。我们已经合作了八年的客户,不需要“欢迎加入我们公司!”插入一个客户,它就发一封邮件;加载一百万个客户,我可不需要一百万封邮件。

**模拟它。自动化不应该运行,但它产生的结果依然是必需的。**一个在创建客户时运行的 flow 会推算出客户细分(Customer Segment)。迁移过来的客户需要一个有效的细分,但把整个 flow 运行五百万次代价太高,或者有副作用。所以我们在转换中计算出细分,把结果加载进去。我们没有忽视业务规则;我们在加载中完成了自动化的工作。

**推迟它。**结果是需要的,但不必在加载事务之内。关掉自动化、设置一个标志进行加载,然后触发一个批处理来补上:重新计算,创建依赖记录,发布下游系统需要的东西。推迟可以让加载更快、更可控,而不放弃结果。

有时你也会让它开着。对于一次较小的加载,如果业务希望它的正常流程运行,就让系统做它该做的事。那也是一种选择,只要它确实是一种选择。

无论你选哪一种,这是我教的规则:**每当你关掉一个自动化,你就要为那段业务逻辑没有执行承担全部责任。**在做决定之前,你需要理解每一个自动化。

Don't need it, simulate it, defer it A decision tree, read left to right, with three questions and four answers. First question: should it happen for migrated data? If no: don't need it, for example status messages to partners for deliveries they closed weeks ago. If yes, the second question: must it happen inside the load? If yes: let it run, deliberately, for example the rule that every Work Order has a partner. If no, the third question: can the preparation set the result, a value rather than a side effect? If yes: simulate it, for example the Work Order's status, mapped in the preparation data store. If no: defer it, for example status history to Snowflake, as one backfill after the load. Underneath, Steve's rule: any time you turn an automation off, you're taking full responsibility for that business logic not happening. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.48.0", "built": "2026-10-27", "id": "DGM-DA-MG-31", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "cells 0.4.0", "theme": "stevetecharc 1.4.0"} THE QUESTIONS THE ANSWERS Should it happen for migrated data? ask it of every automation Must it happen inside the load? or can it come later Can the preparation set the result? a value, not a side effect Don't need it status messages to partners for deliveries closed weeks ago Let it run, deliberately the rule that every Work Order has a partner Simulate it the Work Order's status, mapped in the preparation data store Defer it status history to Snowflake: one backfill after the load no yes yes no yes no Any time you turn an automation off, you're taking full responsibility for that business logic not happening. © 2026 Twinshark LLC · stevetecharc.com
点击放大

Three questions, four answers, one decision per automation. ⟲

Test knowledge. For each automation on a large load, decide: not needed for migrated data (bypass it), needed but its result can be set in the data (simulate it in the transformation), needed but not inside the load (defer it to a batch afterward), or needed inside the load (let it run). Expect a scenario where blindly running automation creates unwanted emails, tasks or integration calls, and one where turning it off silently loses a required result. ⟲

“停用自动化”不是完整的策略

Section titled ““停用自动化”不是完整的策略 ”

计划上写着“停用自动化”。哪个自动化?怎么停,谁来停,什么时候停?我们怎么知道它关了,又怎么知道它重新开了?它通常产生的哪些结果在之后仍然必须存在?如果它关着的时候用户在系统里,或者迁移进行到一半失败了,会怎样?关掉某样东西是一个运维操作。架构需要完整的生命周期:正常状态、迁移状态、恢复正常,以及我们确实恢复了的证明。

And before you decide what to switch off, find out what’s still switched on. Old automation runs on migrated records too. Salesforce ended support for Workflow Rules and Process Builder on December 31, 2025, but “your active Workflow Rules and Process Builder processes continue to run as they did before” (工作流程规则和进程生成器停止支持 (在新标签页中打开), Salesforce Help, checked 2026-10-27). Well-Architected points out the cost: an org “carrying dozens of Process Builders left over from prior implementations … pays to evaluate every one of them on every relevant record save,” and its advice is to “migrate remaining Process Builders to Flow; don’t just deactivate them” (Resource and Cost Optimization (在新标签页中打开), checked 2026-10-27). A migration is a good reason to clear them out first, so 707,000 records aren’t run through automation nobody remembers. ⟲

我更强烈的立场是:**重要的自动化应该有一个受控的绕过机制,即使并没有计划迁移。**迁移不是你需要它的唯一理由。大规模的修复、数据更正、回填、集成修复、紧急恢复:有时你必须在没有全部正常自动化的情况下运行一个受控的操作。如果唯一的办法是在生产环境里修改 flow、停用触发器或删除验证规则,我们就让运维工作变得毫无必要地危险。而且你不能简单地在生产环境里关掉一个触发器:那是一次部署,还要带上它的测试。

The standard answer is a bypass (some teams call it a kill switch): the first thing the trigger or flow does is check a switch, and skip itself if the switch is on. Decide the scope: a global switch for the whole org, one per object, one per automation, or one for particular users, such as the data load user or anyone holding a permission. Put it in your flows as well as your triggers. Flows are easy to deactivate, but a user-specific switch lets everyone else keep working. I consider flows visual programming: whether you’re writing code or programming visually, you’re still programming, and programs need this. ⟲

And here’s the part teams miss: the bypass is part of the original design. It isn’t something you build the week you need it. Every trigger and flow gets its bypass when it’s first built. It’s tested both ways, switched on and switched off, like any other behavior. And it goes to production with the automation, long before any migration, so on cutover weekend it’s already there, already tested, and ready to switch on. A bypass written in a hurry for the load is new, untested code going into production on the riskiest weekend of the project. Salesforce’s Record-Triggered Automation decision guide is just as firm: “A well-architected Salesforce organization requires a consistent and reliable mechanism to bypass automation. This is not an optional feature, but a core operational requirement” (Record-Triggered Automation (在新标签页中打开), Salesforce Architects decision guide, checked 2026-10-27). ⟲

Salesforce says the same thing in its own words. Its Well-Architected list of automation anti-patterns includes “Flows must be manually deactivated prior to bulk data loads” (Automation Patterns (在新标签页中打开), Operational Excellence, checked 2026-10-27). If your load plan says “deactivate these twelve flows on Friday night,” that’s the anti-pattern. ⟲

Test knowledge. Build a bypass into triggers and flows when they’re first built (a check of a custom permission, a custom setting or custom metadata at the start), test it on and off, and deploy it ahead of time, so large loads can skip them without editing or deactivating anything in production. Scope it: by object, by automation, or by user, such as the migration user. Deactivating flows by hand before a bulk load is an anti-pattern in Salesforce’s own Well-Architected guidance. ⟲

So what does a bypass actually look like? Three parts: a place to keep the switch, a check at the top of every trigger and flow, and the same check in the validation rules you decide to relax. Salesforce gives you three places to keep it, and each one decides who the switch applies to. ⟲

Where the switch livesWho it applies toGood for
A custom permission, granted by a permission setOnly the users who hold itThe usual migration bypass: give it to the migration user for the load, take it away after
A hierarchy custom settingThe whole org, one profile, or one userA global “automation off” for everyone, or a switch for one profile or one user
A custom metadata record per automationEveryone, for that one automationSwitching off one specific automation, deployed and versioned like code

The hierarchy custom setting is the one that does global, profile and user in one place. Salesforce’s description: it “checks the organization, profile, and user settings for the current user and returns the most specific, or lowest, value” (Define Custom Settings (在新标签页中打开), Salesforce Help, checked 2026-10-27). Set it off for the org, on for the migration user, and the migration user gets the bypass while everyone else gets normal automation. For most other configuration Salesforce now steers you to custom metadata instead, which deploys with your code; I’d use that for the per-automation switches. ⟲

In Apex, the check is the first thing the trigger does. Here’s what it could look like on the Work Order, with a hierarchy custom setting called Automation_Bypass__c and a custom permission called Bypass_Automation: ⟲

trigger WorkOrderTrigger on WorkOrder (after insert, after update) {
// The hierarchy custom setting: the user's value, else the profile's, else the org's
Automation_Bypass__c settings = Automation_Bypass__c.getInstance();
// Bypass if the setting says so, or if this user holds the custom permission
Boolean bypass = settings.Disable_Triggers__c == true
|| FeatureManagement.checkPermission('Bypass_Automation');
if (bypass) {
return; // no side effects; the record still saves
}
WorkOrderStatusOut.publish(Trigger.new, Trigger.oldMap);
}

getInstance() returns the setting “for the current user,” merged from the lowest level that’s defined (Custom Settings Methods (在新标签页中打开)), and FeatureManagement.checkPermission “checks whether a custom permission is enabled” (FeatureManagement Class (在新标签页中打开); both Apex Reference Guide, Winter ‘27, checked 2026-10-27). ⟲

And one switch per automation, so the bypass is scoped instead of “skip everything.” A custom metadata type, Automation_Switch__mdt, with one record per automation: ⟲

public with sharing class WorkOrderStatusOut {
public static void publish(List<WorkOrder> orders, Map<Id, WorkOrder> oldOrders) {
// One record per automation; switched off here, it's off everywhere it's deployed
Automation_Switch__mdt sw = Automation_Switch__mdt.getInstance('WorkOrder_Status_Out');
if (sw != null && sw.Is_Off__c) {
return;
}
// ... publish the status change for the partners
}
}

getInstance(developerName) reads one custom metadata record by its name (Custom Metadata Type Methods (在新标签页中打开), Apex Reference Guide, checked 2026-10-27). ⟲

In a flow, it’s the same idea: the first element is a decision. ⟲

A bypass at the top of a flow A record-triggered flow, top to bottom. It starts when a Work Order is created or changes. The first element is a question: is the bypass on for this user, through a custom permission or a setting for the org, a profile or one user? If yes, the flow ends and does nothing; the record still saves, with no side effects. If no, the flow carries on to its normal work, highlighted: publish the status to the partners, for everyone else. Underneath: the check comes first; switch it on for the migration user, and the flow steps aside while the record saves. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.48.0", "built": "2026-10-27", "id": "DGM-DA-MG-33", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "flow/decision 0.1.0", "theme": "stevetecharc 1.4.0"} A Work Order is created or changes the record-triggered flow starts Is the bypass on for this user? a custom permission, or a setting for the org, a profile or one user End: do nothing the record still saves; no side effects Publish the status to the partners the normal work, for everyone else yes no The check comes first. Switch it on for the migration user, and the flow steps aside while the record saves. HOW TO READ IT a step the step that matters most a question an answer yes goes right to an answer; no goes down to the next question © 2026 Twinshark LLC · stevetecharc.com
点击放大

The check comes first. Switched on, the flow steps aside. ⟲

The decision’s condition reads the same two switches, through flow’s global variables: $Permission is “the custom permission access of the user running the flow,” and $Setup reads hierarchy custom settings (Global Variables Resource (在新标签页中打开), Salesforce Help, checked 2026-10-27). As a formula resource: ⟲

{!$Permission.Bypass_Automation} || {!$Setup.Automation_Bypass__c.Disable_Flows__c}

In a validation rule, the bypass is one more condition. Here’s R12’s install rule, with the migration user allowed through (the field names are examples): ⟲

AND(
NOT($Permission.Bypass_Automation),
ISPICKVAL(Status, "Completed"),
Install_Required__c,
NOT(Install_Checklist_Complete__c)
)

Validation rules reference a custom permission as $Permission.Custom_Permission_Name (How to Reference a Custom Permission in a Formula, Workflow Rule, or Validation Rule (在新标签页中打开), Salesforce Help, checked 2026-10-27). ⟲

Salesforce’s decision guide calls custom permissions “the modern, scalable standard for implementing bypass logic,” and notes a bypass can be granted to one user, “or even temporarily with a specific expiration date/time” (Record-Triggered Automation (在新标签页中打开), checked 2026-10-27). That’s the migration window, built into the grant. ⟲

These are examples to adapt, not a framework to paste in: build yours, test it in a sandbox, and test that the switch turns back off. And remember what you’ve built. A bypass is a permission to skip business rules. Grant it to the migration user for the migration window, record who has it, and take it away when the load is done (module 4 puts that in the runbook). ⟲

Test knowledge. Know the three places to keep a bypass and who each applies to: a custom permission (only the users whose permission sets grant it; checked with $Permission in flows and validation rules, FeatureManagement.checkPermission in Apex), a hierarchy custom setting (the org, a profile or a user, the most specific value winning; $Setup in flows and formulas, getInstance() in Apex), and custom metadata (one switch per automation, deployable). ⟲

绕过并不意味着迁移用户可以无视 Salesforce 中的每一条规则。这个自动化应该被绕过,那个必须依然运行;一条保护基本不变量的验证规则依然重要,一条通知则不重要;一个下游集成需要被抑制,一个必需的关系依然需要检查。所以我要的绕过是有意的、有范围的,而不是 Migration_Mode__c = true,于是一切都无所谓了。迁移路径依然有规则,只是那些适合迁移的规则。

而且绕过应该代表一种运维上下文,而不是一个意外。一个专门的迁移身份(模块 2)、一项自定义权限、配置元数据、一个功能开关,或它们的组合,都可以识别出经过批准的迁移工作。身份可以是控制的一部分,但我不希望每一个自动化都硬编码成 User.Name = 'Migration User'。那很脆弱。表达出意图:如果这是一次经过批准的迁移操作,就跳过这个副作用。

“当业务机会为 Closed Won 时,Close Date 必填”是一条真正的数据不变量;对历史业务机会也要保留它。一条强制填写三年前才引入的当前流程字段的规则就不同了:十年前的记录从来没有这个字段,编造一个值只会让数据更糟。问题不是“我们要不要关掉验证规则?”而是**哪些规则代表持久的数据真相,哪些代表今天的交互流程?**这是数据架构师的问题。

Steve Trucking has one of each. Every Work Order must have a Retail Partner: that’s enduring truth, and it stays on for the load; a RouteDesk delivery without one goes to quarantine (module 1). But requirement R12 says an install can’t be closed without a completed checklist and specific photos, the water line, the drain line, the level. That’s today’s process, built for crews with the new mobile app. RouteDesk’s completed installs never had those photos. Bypass that rule for the migration identity, and load them as completed. Don’t invent photos. ⟲

要警惕的信号是:目标要求一个值,源数据里没有,于是“统统填上 ‘Unknown’ 就好了”。如果 Unknown 是一个经过批准、确实描述了状态的值,那没问题。如果我们是为了通过验证而插入假值,那就是在为了迎合应用而破坏数据。我宁愿设计一个迁移例外、一个可为空的历史字段、一条转换规则或一个遗留状态值,也不愿假装我们知道自己并不知道的东西。

自动化会把“零的个数”成倍放大

Section titled “自动化会把“零的个数”成倍放大 ”

加载 200 万个客户;自动化为每个客户创建 2 个任务:400 万个任务。这是有意的,还是一个意外?然后每个任务又触发另一个 flow,客户的自动化更新一个父记录,发布一个事件,重新计算别的东西。迁移的性能不是 Bulk API 插入客户的速度。真正的工作负载是这些插入所产生的事务图。“零的个数”会通过自动化成倍放大。

Now zoom in on RouteDesk’s three red arrows and count. ⟲

Automation multiplies the Number of Zeros On the left, highlighted, the load: 196,400 Work Orders, about 190,000 of them already delivered. On the right, what normal automation would reach: Snowflake, for status history; the partners, Redrock, Keystone and Brightwave; the finance ERP, which invoices the partners; and the Recipients, who get day-before texts. First, every arrow is red with an X: 196,400 change events to Snowflake, 190,000 old statuses to the partners, delivery counts already invoiced to the finance ERP, and texts for old deliveries to the Recipients. Then the controlled path: the red arrows are gone; Snowflake gets one backfill after the load, the Recipients get texts only for the open deliveries, as normal, and nothing goes to the partners or the finance ERP. Underneath: the load's real size is every record times everything each record sets off; keep only the outcomes you need. THE LOAD WHAT NORMAL AUTOMATION WOULD DO 196,400 Work Orders about 190,000 already delivered Snowflake status history The partners Redrock, Keystone, Brightwave Finance ERP invoices the partners Recipients day-before texts 196,400 change events 190,000 old statuses counts already invoiced texts for old deliveries The load's real size is every record times everything each record sets off. Keep only the outcomes you need. HOW TO READ IT the load © 2026 Twinshark LLC · stevetecharc.com
点击放大

Every record, times everything it sets off. ⟲

Chapter 9 turned on Change Data Capture for Work Orders, so Snowflake’s subscriber receives a change event for every create. That’s about 196,400 events in one weekend, and without an add-on the daily allocation for delivered events is 50,000 in Performance and Unlimited Editions, counted per subscriber (Change Data Capture Allocations (在新标签页中打开), checked 2026-10-27). The partners would get status messages for about 190,000 deliveries they closed weeks ago. The finance ERP would count deliveries it has already invoiced, and the partners would be billed twice. And Recipients would get texts about deliveries that already happened. ⟲

Automation multiplies the Number of Zeros On the left, highlighted, the load: 196,400 Work Orders, about 190,000 of them already delivered. On the right, what normal automation would reach: Snowflake, for status history; the partners, Redrock, Keystone and Brightwave; the finance ERP, which invoices the partners; and the Recipients, who get day-before texts. First, every arrow is red with an X: 196,400 change events to Snowflake, 190,000 old statuses to the partners, delivery counts already invoiced to the finance ERP, and texts for old deliveries to the Recipients. Then the controlled path: the red arrows are gone; Snowflake gets one backfill after the load, the Recipients get texts only for the open deliveries, as normal, and nothing goes to the partners or the finance ERP. Underneath: the load's real size is every record times everything each record sets off; keep only the outcomes you need. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.48.0", "built": "2026-10-27", "id": "DGM-DA-MG-32", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "cells 0.4.0", "theme": "stevetecharc 1.4.0"} THE LOAD WHAT NORMAL AUTOMATION WOULD DO 196,400 Work Orders about 190,000 already delivered Snowflake status history The partners Redrock, Keystone, Brightwave Finance ERP invoices the partners Recipients day-before texts one backfill, after the load open ones only, as normal The load's real size is every record times everything each record sets off. Keep only the outcomes you need. HOW TO READ IT the load © 2026 Twinshark LLC · stevetecharc.com
点击放大

Keep only the outcomes you need: one backfill, texts for the open deliveries, nothing to partners or finance. ⟲

外部的副作用更糟。客户邮件、账单请求、被生产系统消费的事件、ERP 调用、支持工单、营销更新:那些系统不知道这是迁移数据,而一旦消息离开了 Salesforce,可能就无法撤回了。第 9 章给了我们集成数据契约;在迁移规划期间,要决定这些箭头中哪些可以运行,哪些要被抑制,哪些在切换之后用一次同步来代替。这个决定属于切换计划。

汇总和其他派生值:加载一个父记录,然后是几百万个子记录,每加一个子记录就重新计算一次?也许吧。通常,把一切都加载完再计算一次要便宜得多。问题是,派生结果是必须在迁移期间逐条记录地维护,还是可以在依赖数据完整之后再建立。这还是那个“不需要 / 模拟 / 推迟”的决定。

共享也是派生数据。创建和转移记录会触发共享规则的计算,在一次大型加载中,这可能意味着非常漫长的计算或超时。Salesforce 允许管理员推迟共享计算(共享规则和组成员关系),之后再恢复,但这个功能默认没有开启:要由 Salesforce 客户支持来启用。恢复时,你必须运行一次完整的重新计算,而且为了保护数据完整性,有些共享变化依然会被立即计算(Defer Sharing Calculations (在新标签页中打开))。为它做好计划,也为重新计算的时间做好计划。

Deferring has limits of its own. The catch-up usually runs as batch Apex, and that shares the org’s daily allowance of asynchronous Apex executions: “250,000 or the number of applicable user licenses in your org multiplied by 200, whichever is greater.” Only five batch jobs can be queued or active at once, with up to 100 more waiting in the flex queue (Execution Governors and Limits (在新标签页中打开), Apex Developer Guide, Winter ‘27, checked 2026-10-27). Your catch-up competes with every other batch job in the org, so schedule it, and size it. ⟲

Test knowledge. Large loads trigger sharing recalculation. Salesforce Support can enable deferred sharing calculations (sharing rules and group membership), which you resume and recalculate after the load. Deferred work usually runs as batch Apex, within the daily asynchronous Apex limit and five concurrent batch jobs. ⟲

And sometimes the logic you need is simply too slow to load through. This is the special case module 1 mentioned. A process that takes a second or two per record is fine for users; for hundreds of thousands of records in a cutover window it means days, and trying to simulate an intricate object model in the load can mean a dozen tables. The technique I use: load into a staging object first, a light custom object with no automation that holds the import fields and lookups, then let a batch process work through it, calling the platform’s own logic to build the real records. The status on each staging row lets the batch work in chunks, pause and resume, and the original import fields stay alongside the records they created for tracing. You get the data in fast and catch up on the processing afterward. ⟲

为最终状态而设计,并把它写下来

Section titled “为最终状态而设计,并把它写下来 ”

目标不是“运行生产环境的自动化”。而是**到达正确的生产状态,**这两者并不相同。对于一个新客户,正常的处理会推算出一个分类,创建一个入职任务,发送一条通知,并发布到另一个系统。对于一个迁移过来的历史客户,正确的最终状态可能是:分类要,入职任务不要,欢迎通知不要,外部发布也许要,取决于同步计划。盲目地运行正常的自动化,只会重现一个并非为迁移而设计的流程。

对于一次严肃的迁移,把它写成一份自动化清单:

自动化正常行为迁移决定必需的迁移结果
Status out to partnersSend each status change to Redrock, Keystone, BrightwaveDon’t need itNone: the partners already have it
Change Data Capture to SnowflakeA change event per Work OrderDeferOne backfill of status history after the load
Delivery counts to financeCount each completed delivery for invoicingDon’t need itNone: already invoiced; reconcile the count instead
Day-before textText the Recipient with a tracking linkRun deliberately, open deliveries onlyMonday’s Recipients get the link; none for delivered ones
Work Order statusSet by the crews’ appSimulateStatus mapped in the preparation data store
Install checklist and photos (R12)Block closing an install without themBypass for the migration identityCompleted installs load as completed; no invented photos
Every Work Order has a partnerReject a Work Order without oneKeepMissing partner: quarantined before the load

现在决定是可见的:我们可以评审它、测试它、演练它,并在加载之后验证它。

不要让生产环境成为你第一次使用迁移模式的地方。演练应该测试迁移身份、绕过控制、保持启用的自动化、模拟的结果、推迟的流程以及恢复到正常模式,然后检查:有没有不该触发的东西触发了,有没有该发生的事没有发生,最终状态是否与架构相符?这就是为什么演练需要真实的自动化配置,或者尽可能接近它。

重新启用是一个切换步骤:明确的,有指定的负责人、预期的时间和验证。不是“记得把 flow 重新打开”。在正常运行恢复并经过验证之前,系统还没有为用户准备好(模块 4 把它放进了运行手册)。

And beware the catch-up storm. We suppressed downstream synchronization while loading RouteDesk’s records; now we switch the integration back on. Does it see five million “new” records and try to send them all? Maybe the downstream system already received them another way, maybe only changes after the cutover watermark should go, maybe it needs a controlled initial sync. The automation decision and the integration decision have to work together. Turning automation back on isn’t enough: know what it will do when it wakes up. For Steve Trucking, the status flows and the Change Data Capture subscriber should see only the changes made after cutover, never the weekend’s load. ⟲

现在再加上会对一个新个案、一个被修改的客户、一个已发布的事件或队列中的一个任务做出反应的智能体。迁移会以机器的规模制造数据模式;我们希望智能体对每一条迁移过来的记录都做出反应吗?大概不希望它意外地这样做。由智能体触发的流程,和 flow、触发器、通知、集成和事件一样,都属于这份清单;如果迁移上下文应该抑制它们,就有意识地把这一点设计进去。

**考试之外:AI 改变了什么。**智能体是另一种副作用,它可能会对迁移的数据自主地做出反应。像对待任何其他自动化一样对待由智能体触发的操作:决定是运行、模拟、推迟还是抑制它们,并在演练中测试这个决定。

  • 对每一类迁移数据,哪些自动化运行、不需要、被模拟或被推迟,并清楚关掉一个自动化就意味着要为它的业务逻辑负责。
  • 哪些验证规则代表持久的数据真相,哪些是需要针对迁移特殊处理的当前流程规则。
  • How scoped bypasses are designed into every automation from the start, tested on and off, and deployed long before they’re needed, without an unrestricted “skip everything” path. ⟲
  • 派生数据、共享重新计算和缓慢的平台逻辑如何处理:在加载之后、推迟处理,还是通过暂存对象。
  • 哪些外部副作用和集成被抑制或有意识地补发,以及演练和切换如何证明正常的自动化已被安全恢复。

迁移的成功,不是因为每个 flow 都运行了、每个触发器都触发了、每条验证规则都执行了。那是正常的事务行为,而迁移有一项不同的工作:把数据移入新的架构,保留重要的真相,创建我们需要的派生值,避免错误的副作用,让系统保持可控,然后让它恢复正常。对每一个自动化:不需要它、模拟它、推迟它,或有意让它运行。但要让它成为一个决定。不要让五百万条记录替你决定。