Best way to deal with a change of schema of local data when extension updates

42 views
Skip to first unread message

Moe Bazzi

unread,
Oct 1, 2022, 4:28:49 PM10/1/22
to Chromium Extensions
Hello everyone,

lets say I make a change to the schema (the shape) of some data that is stored in local storage or IndexedDB, what is the best way to handle this when my extension updates to the next version in the users browser?

I would like to run some code to reform the shape of the data only once when the extension version updates. 

Thanks

wOxxOm

unread,
Oct 1, 2022, 6:40:03 PM10/1/22
to Chromium Extensions, bazz...@gmail.com
Add a chrome.runtime.onInstalled listener and check the previousVersion parameter, then change the database accordingly. Or store a separate "dbVersion" value in the database and warn the user if it's higher than the code of the installed extension expects it to be. For the lower values you would add an automatic migration. See also the second parameter of indexedDB.open which is exactly for this purpose. Note that when developing the extension in unpacked mode if you load an older version of the extension from the same folder it won't be able to use the newer database in case your old code explicitly specifies the DB version number parameter. This behavior is intentional to prevent data corruption by an old version of the code.

Robbi

unread,
Oct 2, 2022, 6:43:38 AM10/2/22
to Chromium Extensions, wOxxOm, bazz...@gmail.com
In addition to the very useful indications that wOxxOm gave you, I want to add some of my considerations.
Avoid like the plague to manage this thing with the onUpdateAvailable event because this event is irreversibly "linked" to potential old versions that your users may still have installed.
You would find yourself having to deal with "onUpdateAvailable" + "onInstall" combinations that could give you some headache in the long run.
As for the "in memory" storage (localStorage and \ or browser.storage) there are no big problems;  one method is as good as another (you can operate on one item at a time or create a temporary object that will replace the storage once deleted).

For the indexedDB this is a bit more complicated.
While it is true that at first sight it would be enough to increase the version number of the DB and then manage the version inside the "upgradeneeded" event,
it must remember that inside its handler it can't do everything. We can perform "data definition" operations but not "data modification".
In practice, as long as there is to add\remove an objectStore or an index, no problem. Problems arise when you have to change the structure of an objectstore or you have to translate\modify\aggregate\map its values
In this case it is better to create a new db, launch a conversion procedure (reading from the old one and writing to the new one) and at the end of the procedure delete the old db (after having closed it!).
At that point you will also have to change the code where you open the db and replace the old name with the new one. (it is not possible, as far as I know, to rename an indexedDB).
The operation that I have described to you depends a lot on the size of the DB and therefore it will certainly not be fast.
It is therefore likely that you will need an open window\tab to complete this job since the service worker may suddenly fall asleep.

wOxxOm

unread,
Oct 2, 2022, 8:04:01 AM10/2/22
to Chromium Extensions, Robbi, wOxxOm, bazz...@gmail.com
>  you will also have to change the code where you open the db and replace the old name with the new one

A universal solution might be to add the dbVersion as a suffix in the name: indexedDB.open('someName' + dbVersion, dbVersion)

> It is therefore likely that you will need an open window\tab to complete this job since the service worker may suddenly fall asleep.

Yeah, this architectural bug is very dangerous because it randomly affects users and corrupts their data. Not all things can be wrapped in a transaction, and even IndexedDB is rarely used with write transactions since it reduces performance and wasn't required previously. Until https://crbug.com/1364120 is fixed (still no response from the dev team) this will happen randomly when the unsuspecting users invoke the extension in the last moments of its 30-second lifespan for the background script. ManifestV3 developers should stop pretending that nontrivial extensions don't exist or that the negative impact is not so bad, it really is bad, really bad. I wonder if Chrome could ask a question before terminating a busy background script like it does when a page seems to hang.

Reply all
Reply to author
Forward
0 new messages