mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 09:06:06 +00:00
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
118 lines
5.1 KiB
Python
118 lines
5.1 KiB
Python
from django.apps import AppConfig
|
|
import os
|
|
import sys
|
|
from django.db.models.signals import post_migrate
|
|
|
|
|
|
class PluginsConfig(AppConfig):
|
|
name = "apps.plugins"
|
|
verbose_name = "Plugins"
|
|
|
|
def ready(self):
|
|
"""Wire up plugin discovery without hitting the DB during app init.
|
|
|
|
- Skip during common management commands that don't need discovery.
|
|
- Register post_migrate handler to sync plugin registry to DB after migrations.
|
|
- 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
|
|
if os.environ.get("DISPATCHARR_SKIP_PLUGIN_AUTODISCOVERY", "").lower() in ("1", "true", "yes"):
|
|
return
|
|
|
|
argv = sys.argv[1:] if len(sys.argv) > 1 else []
|
|
mgmt_cmds_to_skip = {
|
|
# Skip immediate discovery for these commands
|
|
"makemigrations", "collectstatic", "check", "test", "shell", "showmigrations",
|
|
}
|
|
if argv and argv[0] in mgmt_cmds_to_skip:
|
|
return
|
|
|
|
# Run discovery with DB sync after the plugins app has been migrated
|
|
def _post_migrate_discover(sender=None, app_config=None, **kwargs):
|
|
try:
|
|
if app_config and getattr(app_config, 'label', None) != 'plugins':
|
|
return
|
|
from .loader import PluginManager
|
|
PluginManager.get().discover_plugins(sync_db=True)
|
|
except Exception:
|
|
import logging
|
|
logging.getLogger(__name__).exception("Plugin discovery failed in post_migrate")
|
|
|
|
post_migrate.connect(
|
|
_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
|
|
except Exception:
|
|
# Avoid breaking startup due to plugin errors
|
|
import logging
|
|
|
|
logging.getLogger(__name__).exception("Plugin discovery wiring failed during app ready")
|
|
|
|
# Register periodic task for refreshing plugin repo manifests
|
|
self._setup_repo_refresh_schedule()
|
|
|
|
# Refresh repo manifests once at startup so the UI always has current data
|
|
self._enqueue_startup_refresh()
|
|
|
|
def _enqueue_startup_refresh(self):
|
|
from dispatcharr.app_initialization import should_skip_initialization
|
|
if should_skip_initialization():
|
|
return
|
|
try:
|
|
from .tasks import refresh_plugin_repos
|
|
refresh_plugin_repos.apply_async(countdown=10)
|
|
except Exception:
|
|
import logging
|
|
logging.getLogger(__name__).debug(
|
|
"Could not enqueue startup plugin repo refresh (Celery may not be ready yet)"
|
|
)
|
|
|
|
def _setup_repo_refresh_schedule(self):
|
|
from dispatcharr.app_initialization import should_skip_initialization
|
|
if should_skip_initialization():
|
|
return
|
|
try:
|
|
from core.scheduling import create_or_update_periodic_task, delete_periodic_task
|
|
from core.models import CoreSettings
|
|
from .tasks import PLUGIN_REPO_REFRESH_TASK_NAME
|
|
|
|
interval = 6
|
|
try:
|
|
obj = CoreSettings.objects.get(key="plugin_repo_settings")
|
|
interval = obj.value.get("refresh_interval_hours", 6)
|
|
except CoreSettings.DoesNotExist:
|
|
pass
|
|
|
|
if interval == 0:
|
|
delete_periodic_task(PLUGIN_REPO_REFRESH_TASK_NAME)
|
|
else:
|
|
create_or_update_periodic_task(
|
|
task_name=PLUGIN_REPO_REFRESH_TASK_NAME,
|
|
celery_task_path="apps.plugins.tasks.refresh_plugin_repos",
|
|
interval_hours=interval,
|
|
enabled=True,
|
|
)
|
|
except Exception:
|
|
import logging
|
|
logging.getLogger(__name__).debug(
|
|
"Could not set up plugin repo refresh schedule (migrations may not have run yet)"
|
|
)
|