System Updates¶
A system update is a one-off change to the data in Mongo that ships with a code change: drop a retired collection, backfill a new field, pull a deleted extension out of every page. Each one runs once per database, at start-up, before the app initialises anything else.
They are different from platform upgrades (SiteUpgrade, listed under Settings > Platform
upgrades), which an admin chooses to apply to one site. A system update is global and mandatory.
Adding one¶
Add a JSON file to commerce-core/src/main/resources/systemUpdates, named
yyyy-MM-dd-what-it-does.json with today's date:
[ "uk.co.kedos.badger.settbuilder.system.update.beans.DeleteAll", {
"collectionName" : "repositoryChangeBean"
} ]
The file describes one DataChangeOperation (in system/update/beans): Insert, InsertIfAbsent,
Delete, DeleteAll (drops the collection), Rename, UpdateField,
UpdateFieldInMultipleRecords, or a custom one in beans/custom when the change needs code. A
custom operation gets a unit test that loads its JSON file, as BackfillSiteTimeZonesTest does.
Write updates so that running one twice does no harm (InsertIfAbsent rather than Insert for a
document fresh installs also create). A failing update stops the run and is retried at every start
until it succeeds, so one that can never succeed holds back every update after it.
Names and order¶
Updates up to 113 are named 1.json to 113.json. They run first, in number order. Named updates
run after them, in name order, so the date sets the order. Don't add a numbered update:
SystemUpdateFilesTest fails on any number above 113, and checks that every file parses.
Numbers clashed: two branches would both take the next number, and once one had run on an environment the other was skipped there. Dated names make a clash unlikely, and a real one is a merge conflict on the same file name.
How it runs¶
BadgerDataChanger runs from BadgerInitialiser when each app starts.
- The ledger. Each applied update is recorded in the
systemUpdateLogcollection (_id= the name,appliedAt,appliedBy= node,changed= records changed). Any update not in it runs, so an update from a branch that merges after a later-dated one still runs. - The first start. An empty ledger is seeded from the old
lastRanDataChangerIDglobal setting: numbered updates up to it count as applied. A database with no such setting is new, and is about to be initialised from current seed data, so every update it ships with counts as applied (appliedBy: baseline). - The lease. Every app that includes commerce-core runs this, so during a rollout several pods
start at once. The first takes a ten-minute lease in
systemUpdateLock; the others wait up to two minutes for it to finish, then start without running anything. A lease left by a pod that died expires on its own.
To run an update again on an environment, delete its entry from systemUpdateLog and restart.