mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-17 16:50:53 +00:00
fix: Ensure plugin discovery runs in all non-Celery processes to apply monkey-patches in uWSGI workers
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
This commit is contained in:
parent
eba261b6af
commit
f4dce6db01
2 changed files with 17 additions and 9 deletions
|
|
@ -92,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- **DVR section count badges appeared at the far right of the screen.** The "Currently Recording", "Upcoming Recordings", and "Previously Recorded" section headers wrapped the title and badge in a `Group justify="space-between"`, which pushed the badge to the opposite edge of the full-width container. Changed to `Group gap="xs" align="center"` so each badge sits inline with its heading.
|
||||
- **Plugin event dispatch aborted silently on first disabled plugin.** `trigger_event` in `apps/connect/utils.py` iterated `pm.list_plugins()` and, for disabled plugins, logged a debug message using `plugin.key` / `plugin.name` (attribute access). Because `list_plugins()` returns dicts, this raised `AttributeError` on the first disabled plugin encountered. Fixed by changing the two accesses to `plugin['key']` / `plugin['name']`. (Fixes #1231) - Thanks [@R3XCHRIS](https://github.com/R3XCHRIS)
|
||||
- **Plugin periodic tasks silently missed the first beat tick after every Celery worker restart.** Plugin modules live outside `INSTALLED_APPS` so `autodiscover_tasks()` never imports them, and worker startup skips plugin discovery via `should_skip_initialization()`. Any plugin using module-level `@shared_task` had its tasks unregistered with the worker until a lazy event import warmed the module; beat fired on schedule but the worker rejected with `Received unregistered task` and advanced `last_run_at` anyway, hiding the miss. A `worker_ready` hook in `dispatcharr/celery.py` now eagerly calls `PluginManager.discover_plugins(sync_db=False)` on every worker boot so plugin tasks are registered before beat starts firing. (Fixes #1244) - Thanks [@R3XCHRIS](https://github.com/R3XCHRIS)
|
||||
- **Plugin monkey-patches and module-level hooks were never applied in uWSGI workers.** Both uWSGI configs use `lazy-apps=true`, meaning each worker boots independently and never inherits state from the master. `should_skip_initialization()` correctly skipped one-shot startup tasks in workers, but also blocked `discover_plugins`, so plugin modules were never imported in any of the 4 request-serving workers. Plugins relying on patching request handling (monkey-patches, signal registrations) were silently inactive until a Connect event lazily triggered discovery in that specific worker. Discovery is now run in every process that serves requests, gated only for Celery processes (which use `worker_ready`) and management commands that don't serve requests.
|
||||
|
||||
### Performance
|
||||
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@ class PluginsConfig(AppConfig):
|
|||
|
||||
- Skip during common management commands that don't need discovery.
|
||||
- Register post_migrate handler to sync plugin registry to DB after migrations.
|
||||
- Do an in-memory discovery (no DB) so registry is available early
|
||||
but only in the main uwsgi/daphne process. Celery workers and
|
||||
management commands skip the eager pass: the post_migrate handler
|
||||
covers the DB sync, and `connect/utils.py` lazy-discovers on first
|
||||
event using the loader's cache.
|
||||
- Run in-memory discovery (no DB) in every non-Celery process so plugin
|
||||
modules are imported and monkey-patches apply. This includes uWSGI workers
|
||||
under lazy-apps=true, which each start cold and never inherit a warmed fork.
|
||||
Celery workers skip here and discover via the worker_ready signal instead.
|
||||
- One-shot startup tasks (schedule setup, repo refresh) are gated by
|
||||
should_skip_initialization() so they only fire in the master/main process.
|
||||
"""
|
||||
try:
|
||||
# Allow explicit opt-out via env var
|
||||
|
|
@ -47,13 +48,19 @@ class PluginsConfig(AppConfig):
|
|||
_post_migrate_discover,
|
||||
dispatch_uid="apps.plugins.post_migrate_discover",
|
||||
)
|
||||
#
|
||||
|
||||
from dispatcharr.app_initialization import should_skip_initialization
|
||||
# Skip discovery for Celery (worker_ready signal handles it) and
|
||||
# pure management commands that don't serve requests. Every other
|
||||
# process - including each uWSGI worker under lazy-apps=true - runs
|
||||
# discovery so plugin modules are imported and monkey-patches apply.
|
||||
_no_discovery_cmds = {'celery', 'beat', 'migrate', 'dbshell', 'loaddata'}
|
||||
if not any(cmd in sys.argv for cmd in _no_discovery_cmds):
|
||||
from .loader import PluginManager
|
||||
PluginManager.get().discover_plugins(sync_db=False)
|
||||
|
||||
if should_skip_initialization():
|
||||
return
|
||||
|
||||
from .loader import PluginManager
|
||||
PluginManager.get().discover_plugins(sync_db=False)
|
||||
except Exception:
|
||||
# Avoid breaking startup due to plugin errors
|
||||
import logging
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue