Bootstrap events

324 views
Skip to first unread message

Emiliano Heyns

unread,
Jun 2, 2023, 7:04:40 PM6/2/23
to zotero-dev
Is there documentation on under what circumstances the bootstrap events  (install, startup, shutdown, uninstall) are called? And if I provide async handlers for EG shutdown , are those guaranteed to run to completion before zotero itself shuts down?

Dan Stillman

unread,
Jun 3, 2023, 5:24:14 AM6/3/23
to zoter...@googlegroups.com
On 6/2/23 7:04 PM, Emiliano Heyns wrote:
> Is there documentation on under what circumstances the bootstrap
> events  (install, startup, shutdown, uninstall) are called?

Yes, they're documented in the archived MDN link from here:

https://www.zotero.org/support/dev/zotero_7_for_developers#xul_overlays_bootstrapjs

> And if I provide async handlers for EG shutdown , are those guaranteed
> to run to completion before zotero itself shuts down?

No. That would potentially cause unpredictable slowdowns or hangs at
shutdown, which we don't really want to allow. Is there a reason you
want that?

Emiliano Heyns

unread,
Jun 3, 2023, 5:24:30 AM6/3/23
to zotero-dev

Also be aware that in some circumstances an add-on upgrade/downgrade may occur without the uninstall method being called.

Should I just ignore install and uninstall and just perform the install/uninstall actions on startup/shutdown?

Emiliano Heyns

unread,
Jun 3, 2023, 5:28:02 AM6/3/23
to zotero-dev
I need to flush my data to the database at shutdown; the Zotero shutdown proceeds while my shutdown listener is running, removing access to the Zotero database before I'm done.

Emiliano Heyns

unread,
Jun 3, 2023, 5:30:19 AM6/3/23
to zotero-dev
https://udn.realityripple.com/docs/Archive/Add-ons/Bootstrapped_extensions lists examples of when the events are called, but not really a structured explanation of which these are samples.

Emiliano Heyns

unread,
Jun 3, 2023, 5:38:25 AM6/3/23
to zotero-dev
> Yes, they're documented in the archived MDN link from here:

OK, so if my plugin is upgraded I should expect to see

- old: shutdown
- old: uninstall
- new: install
- new startup

and for uninstall always

- shutdown
- uninstall

always without exception

On Saturday, June 3, 2023 at 11:24:14 AM UTC+2 Dan Stillman wrote:

Emiliano Heyns

unread,
Jun 3, 2023, 5:54:27 AM6/3/23
to zotero-dev
And I'm seeing my own shutdown transactions being aborted because zotero is going ahead with shutdown.

Dan Stillman

unread,
Jun 3, 2023, 5:58:42 AM6/3/23
to zoter...@googlegroups.com
On 6/3/23 5:38 AM, Emiliano Heyns wrote:
> > Yes, they're documented in the archived MDN link from here:
>
> OK, so if my plugin is upgraded I should expect to see
>
> - old: shutdown
> - old: uninstall
> - new: install
> - new startup
>
> and for uninstall always
>
> - shutdown
> - uninstall
>
> always without exception

Actually, I don't think so. It doesn't look like `shutdown` and
`uninstall` are currently called on updates. I think that's probably
better — it makes more sense for the plugin to just store its last-known
version and perform any necessary upgrades on `install` than to do a lot
of pointless `uninstall` work.

We'll update the documentation with the current behavior. We can also
see if it's possible to pass ADDON_UPGRADE for a reason in `install` and
`startup`.

Dan Stillman

unread,
Jun 3, 2023, 6:03:15 AM6/3/23
to zoter...@googlegroups.com
On 6/3/23 5:58 AM, Dan Stillman wrote:
> Actually, I don't think so. It doesn't look like `shutdown` and
> `uninstall` are currently called on updates.

To be clear, this is referring to Zotero 7, which reimplements the
bootstrap behavior based on the current Mozilla add-on manager. It's
possible those are called for updates in Zotero 6.

Dan Stillman

unread,
Jun 3, 2023, 6:11:15 AM6/3/23
to zoter...@googlegroups.com
On 6/3/23 5:28 AM, Emiliano Heyns wrote:
> I need to flush my data to the database at shutdown; the Zotero
> shutdown proceeds while my shutdown listener is running, removing
> access to the Zotero database before I'm done.

Is this with Zotero 6 or Zotero 7? We can't do anything about Zotero 6
bootstrap, but we can consider giving Zotero 7 plugins a very small
amount of time to complete tasks at shutdown.

Emiliano Heyns

unread,
Jun 3, 2023, 6:14:58 AM6/3/23
to zotero-dev
> Actually, I don't think so. It doesn't look like `shutdown` and
> `uninstall` are currently called on updates. I think that's probably
> better — it makes more sense for the plugin to just store its last-known
> version and perform any necessary upgrades on `install` than to do a lot
> of pointless `uninstall` work.

That would be a problem for me. I think I can find a workaround, but currently I do (like in the make it red plugin) a test at startup:

if (!Zotero.MakeItRed) {

and that would always fail after an upgrade if I hadn't issued a

delete Zotero.MakeItRed

in something like the shutdown of the old.

Or I'd have to do this using reason + oldVersion (or the oldVersion saved in a preference) + newVersion, but then I'd need to know what I can expect from these at bootstrap method calls.

Emiliano Heyns

unread,
Jun 3, 2023, 6:17:09 AM6/3/23
to zotero-dev
> we can consider giving Zotero 7 plugins a very small
> amount of time to complete tasks at shutdown.

Doing it for 7 would suffice. I can use a AsyncShutdown.profileBeforeChange.addBlocker for Z6. Those also have limited time, but enough for my needs.

Dan Stillman

unread,
Jun 3, 2023, 6:25:23 AM6/3/23
to zoter...@googlegroups.com
On 6/3/23 6:14 AM, Emiliano Heyns wrote:
> > Actually, I don't think so. It doesn't look like `shutdown` and
> > `uninstall` are currently called on updates. I think that's probably
> > better — it makes more sense for the plugin to just store its
> last-known
> > version and perform any necessary upgrades on `install` than to do a
> lot
> > of pointless `uninstall` work.
>
> That would be a problem for me. I think I can find a workaround, but
> currently I do (like in the make it red plugin) a test at startup:
>
> if (!Zotero.MakeItRed) {
>
> and that would always fail after an upgrade if I hadn't issued a
>
> delete Zotero.MakeItRed
>
> in something like the shutdown of the old.

I'm not actually sure why that's there. lib.js is only loaded from
bootstrap.js's startup(), so I think that can just overwrite.

Emiliano Heyns

unread,
Jun 3, 2023, 10:45:21 AM6/3/23
to zotero-dev
Can I reliably distinguish between my plugin being disabled, being upgraded, and zotero being shut down?

Dan Stillman

unread,
Jun 3, 2023, 5:59:24 PM6/3/23
to zoter...@googlegroups.com
On 6/3/23 10:45 AM, Emiliano Heyns wrote:
> Can I reliably distinguish between my plugin being disabled, being
> upgraded, and zotero being shut down?

- being disabled → shutdown() with reason ADDON_DISABLE

- being upgraded → for now, install() with a newer version number than
you last stored; we'll try to add ADDON_UPGRADE to install() and startup()

- Zotero being shut down → shutdown() with reason APP_SHUTDOWN

Emiliano Heyns

unread,
Jun 4, 2023, 5:24:08 AM6/4/23
to zotero-dev
Clear. Sorry to press the matter, but BBT does things like reinit of the translators and I'm trying to get things right. I think what's below covers all scenarios (correct?) how can I distinguish (in 6 and 7)

- Clean install:?
- Upgrade: for now, install() with a newer version number than
you last stored
- Disable: shutdown() with reason ADDON_DISABLE
- Enable:?
- Uninstall:?
- zotero Shutdown : shutdown() with reason APP_SHUTDOWN

Did I miss a scenario?

Emiliano Heyns

unread,
Jun 4, 2023, 5:49:51 AM6/4/23
to zotero-dev
And for completeness: in such a way that I can't confuse them with other scenarios, eg if startup would be called for re-enable and clean start from pre-installed (which is a scenario I missed above, but come to think of it, these aren't really separate scenarios at all)

Dan Stillman

unread,
Jun 4, 2023, 5:50:27 AM6/4/23
to zoter...@googlegroups.com
On 6/4/23 5:24 AM, Emiliano Heyns wrote:
> Clear. Sorry to press the matter, but BBT does things like reinit of
> the translators and I'm trying to get things right. I think what's
> below covers all scenarios (correct?) how can I distinguish (in 6 and 7)
>
> - Clean install:?
> - Upgrade: for now, install() with a newer version number than
> you last stored
> - Disable: shutdown() with reason ADDON_DISABLE
> - Enable:?
> - Uninstall:?
> - zotero Shutdown : shutdown() with reason APP_SHUTDOWN
>
> Did I miss a scenario?


- Clean install: install() with ADDON_INSTALL or nothing stored

- Upgrade: for now, install() with a newer version number than you last
stored (see note below)

- Disable: shutdown() with reason ADDON_DISABLE

- Enable: startup() with ADDON_ENABLE

- Uninstall: uninstall() with reason ADDON_UNINSTALL (see note below)

- Zotero shutdown : shutdown() with reason APP_SHUTDOWN


This is Zotero 7. Zotero 6 should be as documented by Mozilla, so same
as above but with an extra shutdown() and uninstall() with
ADDON_UPGRADE/ADDON_DOWNGRADE during a version change.

We're also going to see if we can restore that upgrade/downgrade
behavior in Zotero 7. Thinking about it more, I realized that the new
(or even old) version being installed doesn't necessarily know how to
undo all the things that the previous version did, so having each
version do its own uninstall before a version change makes more sense.

Emiliano Heyns

unread,
Jun 4, 2023, 11:21:23 AM6/4/23
to zotero-dev
Correct, I rely on each version being able to do it's own shutdown/ uninstall.

Install with nothing stored could also be the first upgrade where the plugin starts storing the last installed version. ADDON_INSTALL or nothing

Emiliano Heyns

unread,
Jun 4, 2023, 11:23:23 AM6/4/23
to zotero-dev
So for a clean install, no startup is fired? Or is it fired with ADDON_INSTALL?

Emiliano Heyns

unread,
Jun 5, 2023, 3:42:42 AM6/5/23
to zotero-dev
On the assumption that these constants are correct:

const BOOTSTRAP_REASONS = {
  APP_STARTUP     : 1,
  APP_SHUTDOWN    : 2,
  ADDON_ENABLE    : 3,
  ADDON_DISABLE   : 4,
  ADDON_INSTALL   : 5,
  ADDON_UNINSTALL : 6,
  ADDON_UPGRADE   : 7,
  ADDON_DOWNGRADE : 8
};

I'm seeing on Zotero 6:

clean install: install(ADDON_INSTALL), startup(ADDON_INSTALL)
upgrade: shutdown(ADDON_UPGRADE), uninstall(ADDON_UPGRADE), install(ADDON_UPGRADE), startup(ADDON_UPGRADE)
same-version install: shutdown(ADDON_DOWNGRADE), uninstall(ADDON_DOWNGRADE), install(ADDON_DOWNGRADE), startup(ADDON_DOWNGRADE)
disable: shutdown(ADDON_DISABLE)
enable: startup(ADDON_ENABLE)
uninstall: shutdown(ADDON_UNINSTALL)
shutdown: shutdown(APP_SHUTDOWN)

Zotero 7:
install: install(no reason), startup(ADDON_INSTALL)
same-version install: install(no reason), startup(ADDON_INSTALL)
upgrade: install(no reason), startup(ADDON_INSTALL)
disable: shutdown(ADDON_DISABLE)
enable: startup(ADDON_ENABLE)

Emiliano Heyns

unread,
Jun 5, 2023, 6:38:18 AM6/5/23
to zotero-dev
So across 6/7, it looks to me the following will work for me:

install (any reason):
flush databases if BBT is running

shutdown(ADDON_DISABLE or
ADDON_UNINSTALL): flush databases, remove existing translators & reinittranslators
shutdown(ADDON_DOWNGRADE, ADDON_UPGRADE or
APP_SHUTDOWN):flush databases
startup (any reason)
: perform startup

uninstall (any reason)
: ignore

Emiliano Heyns

unread,
Jun 8, 2023, 7:09:43 AM6/8/23
to zotero-dev

Are the bootstrap handlers async-aware? That is, if I have `async funtion install(...)` is that guaranteed to run to completion before the consequent `startup(...)` is called?

Emiliano Heyns

unread,
Jun 8, 2023, 5:12:42 PM6/8/23
to zotero-dev
It doesn't look like it, at least during clean install on 6, async startup is started before async install finishes. That's actually a problem for me, I need to be able to shut down the existing version before the new version starts during upgrades. It's easy enough to force these two to serialize using a deferred, but I'd need to know exact startup sequences for each possible scenario, and orchestrating them during upgrades will involve orchestrating code running in the memory space of the old version and the new version.

Emiliano Heyns

unread,
Jun 9, 2023, 2:09:42 AM6/9/23
to zotero-dev
I did miss at least one scenario -- the extension can be uninstalled while disabled, and then the uninstall event handler is not ran at all.

Dan Stillman

unread,
Jun 12, 2023, 1:47:39 AM6/12/23
to zoter...@googlegroups.com
Turns out this was the same bug — with that fixed, we do in fact await
shutdown handlers. We'll likely limit how long these can run, but you
should be able to do some very quick cleanup steps if necessary.

Emiliano Heyns

unread,
Jun 12, 2023, 3:17:09 AM6/12/23
to zotero-dev
Is there a timeline for this to appear in the beta's? I don't really want to release a BBT compatible with the beta's if I can't do a safe flush.

Emiliano Heyns

unread,
Jun 30, 2023, 6:02:37 AM6/30/23
to zotero-dev
Any news on this?

Dan Stillman

unread,
Jul 1, 2023, 7:07:43 AM7/1/23
to zoter...@googlegroups.com
On 6/4/23 5:50 AM, Dan Stillman wrote:
> Zotero 6 should be as documented by Mozilla, so same as above but with
> an extra shutdown() and uninstall() with ADDON_UPGRADE/ADDON_DOWNGRADE
> during a version change.
>
> We're also going to see if we can restore that upgrade/downgrade
> behavior in Zotero 7. Thinking about it more, I realized that the new
> (or even old) version being installed doesn't necessarily know how to
> undo all the things that the previous version did, so having each
> version do its own uninstall before a version change makes more sense.

I've made this change in the latest beta. When moving between plugin
versions, the current version's shutdown() (if active) and uninstall()
methods will be called.

If those methods return promises, they'll be awaited (though, again, we
reserve the right to be very strict about how much time they get).

While fixing this, I realized that we weren't properly loading the new
version's code or creating a new scope when moving between versions, so
that's fixed now as well. There may be a couple other lifecycle bugs to
fix (e.g., behavior when changes are made while a plugin is disabled).

Emiliano Heyns

unread,
Jul 1, 2023, 10:00:53 AM7/1/23
to zotero-dev
For me there isn't a relevant difference in that last case, if a plugin is disabled it should leave zotero exactly like if it were un-installed I think.

Emiliano Heyns

unread,
Jul 2, 2023, 6:35:11 PM7/2/23
to zotero-dev
In the beta the bootstrap methods are called after the Zotero object has been loaded, right? I'm getting `Zotero is undefined` at `if (Zotero.BetterBibTeX)`

  async function startup({ resourceURI, rootURI = resourceURI.spec }, reason) {
    const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup);
    const manifestURI = Services.io.newURI(`${rootURI}manifest.json`);
    chromeHandle = aomStartup.registerChrome(manifestURI, [
  [ "content", "zotero-better-bibtex", "content/" ],
  [ "locale", "zotero-better-bibtex", "en-US", "locale/en-US/" ],
  [ "locale", "zotero-better-bibtex", "fr-FR", "locale/fr-FR/" ],
  [ "locale", "zotero-better-bibtex", "pt-BR", "locale/pt-BR/" ]
]);
    if (Zotero.BetterBibTeX) throw new Error("Better BibTeX is already started");
    setDefaultPrefs(rootURI);
    Services.scriptloader.loadSubScript(`${rootURI}content/better-bibtex.js`, {
      Zotero,
      setTimeout,
      clearTimeout,
      setInterval,
      clearInterval
    }, "utf-8");
    await Zotero.BetterBibTeX.startup(BOOTSTRAP_REASONS[reason]);
  }
Message has been deleted

Emiliano Heyns

unread,
Jul 3, 2023, 2:53:01 AM7/3/23
to zotero-dev

Never mind -- I had `var Zotero` at the top, which apparently kills the Zotero object. I've moved to a overlay/bootstrapped model, and I only partially took out the 6/7 bootstrap compat code.

Scary -- looks like I might have finished a 6/7beta-compatible build.
Reply all
Reply to author
Forward
0 new messages