MB-820 study materials
MB-820 study resources

Promoting a per-tenant extension to 14 tenants without losing data

MB-820 · Put your knowledge to work in context.

All case studies

Promoting a per-tenant extension to 14 tenants without losing data

Fabrikam Consulting maintains a per-tenant extension called WarehousePlus, currently version 2.3.0.0, deployed to 14 customer tenants, three of them production. Release 3.0 renames field 50110 "Qty" to "Quantity" on table 50120 "Bin Content" and changes field 50121 "Status" from Option to Enum. Two customers have page extensions on table 50120 that reference both fields. Developers publish from Visual Studio Code directly to whichever tenant a bug was reported on; last quarter a publish to production removed a table that had been deleted from the extension, and the customer lost three days of data. There is no automated build, and sandboxes are refreshed monthly.

1. Design the release process for this extension. What must change before release 3.0 ships?

Read the worked answer

Introduce a one-way promotion pipeline and stop publishing from developer workstations to anything a customer uses.

  • Build: every merge produces a versioned, signed artifact (.app) from source control. Version number is part of the artifact, never edited by hand at publish time.
  • Environments: development sandbox → test sandbox (restored from a production backup) → production. A build only moves forward; a hotfix is a new version, not a re-publish of the same one.
  • Validation gate: the artifact is installed and the upgrade codeunit is executed against a restored copy of real data before production approval. This is the only way to see what the schema sync will do.
  • Production publish happens in a scheduled window, by the pipeline (service-to-service), not by a developer, with a recent environment backup available for restore.
  • Versioning discipline across 14 tenants: some tenants will be on 3.0 and some still on 2.3 for weeks. The artifact must therefore support the older data shape until every tenant is upgraded - a reason to avoid destructive changes in a minor-step release.

The judgment being tested: deployment is a process with a rollback story, and the existence of multiple tenants on different versions constrains how aggressively you can change schema.

2. How should the Qty→Quantity rename and the Option→Enum change be performed?

Read the worked answer

Do not rename or retype in place. Use add-and-migrate, then remove later:

  1. Add new field Quantity (Decimal) alongside Qty, and a new Enum-based Status field alongside the Option field.
  2. Mark the old fields with ObsoleteState = Pending and point ObsoletedBy at the new field, so dependent code still compiles with a warning while the customers' page extensions are updated.
  3. Migrate in an upgrade codeunit: for each company, copy Qty into Quantity and map the Option value onto the corresponding Enum value. Enum extension members can carry the same numeric values as the old Option, which makes the mapping mechanical; still verify each tenant's actual values rather than assuming.
  4. Freeze writes to the old field: update all page and code paths to the new field, and let the old one become read-only.
  5. Remove the old fields only in a later major release, after all 14 tenants are on a version that no longer references them.

Why this order: the two customers' page extensions are compiled against the old field names. If the rename happens in the same release as the field removal, their extensions fail to compile or fail at runtime, and the partner owns the outage. Obsoletion gives a deprecation window with a warning instead of an error. The migration must be idempotent - an upgrade step can be re-run after a failure, so guard it by checking the target field.

3. What controls prevent a repeat of the deleted-table data loss?

Read the worked answer

Separate the technical control from the process control:

  • Technical: removing a table from an extension drops its data during schema synchronization. Treat table removal as a destructive operation requiring an explicit obsolete period: first mark the table ObsoleteState = Pending so data survives and code stops referencing it, and remove it only after at least one full release cycle.
  • Process: destructive changes require a second reviewer and a stated data-retention justification on the pull request. "We don't use it" from one tenant is not that justification when 14 tenants share the codebase.
  • Evidence: before every production publish, run the upgrade against a restored copy of that tenant's production data, then compare record counts and a sample of key totals. Schema sync issues surface here, not in production.
  • Recovery: confirm the environment's backup and point-in-time restore capability and the actual restore time before you need it. A backup nobody has restored is a hypothesis.
  • Detection: emit telemetry from the upgrade codeunit and alert on upgrade failures so the next incident is measured in minutes, not three days.

Judgment point: the incident was caused by a destructive change shipped without a data check. The fix is a policy about destructive changes plus a rehearsal on real data, not merely "use a pipeline."