Repository navigation
Conversation
health, inventory-import, and tailscale call ctx.settings.get() inside activate(), which runs before the daemon client exists. That raised BackendUnavailable and the loader dropped the plugin (issue #1342). Retry the activation once the client is connected, just before app_started, so the read returns the stored value instead of abandoning the plugin. Other activate() errors are still fatal, and the daemon process does not retry. Co-authored-by: newmfat <newmfat@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Enabled user plugins that call
ctx.settings.get()insideactivate()were dropped at startup.health,inventory-import, andtailscaleall do that, and plugin loading runs before the daemon client exists, so each read raisedBackendUnavailableand the loader logged the traceback from issue #1342 and skipped the plugin. The app itself kept going.Settings still raise while the client is missing — a silent default is indistinguishable from "unset", and a later write of that default would erase stored values. The GTK loader now catches that error and runs
activate()again once, immediately beforeapp_started, when the window is bound and the client can answer. The persisted value is what the plugin reads. Any pages or event subscriptions from the failed attempt are removed first, soapp_startedis delivered once. If the client never connects, the plugin stays unloaded. Any other exception duringactivate()is still fatal. The daemon process does not retry, because it has no client to attach later.Fixes #1342.
API and architecture
core/frontend ownership boundary
docs/api/CHANGELOG.mdwas updatedPlugin settings remain daemon-owned. The only change is when the GTK loader finishes activating a user plugin that touched them too early.
docs/PLUGIN_SDK.mdanddocs/plugins/writing-plugins.mddescribe the retry.Testing
Reproduced the drop before the change: a user plugin that calls
ctx.settings.get()inactivate()was absent from the loaded list after the window was presented and the backend settled, with the sameBackendUnavailabletraceback as the issue (plugins/api.pyget/_client).After the change:
95 passed, 1 skipped. The new loader cases cover a successful retry (stored value, not the caller's default;
app_startedonce), client selection resolving before the window is bound, a Plugins page rebuilt after the late load, a backend that never connects, a non-backendactivate()error, and the daemon path still refusing to wait.