Phase 1: Fix all critical release blockers (B1-B10)
B1: Remove duplicate get_redis() — singleton no longer overwritten B2: Plugin routes now enforce activation status via require_active_plugin() B3: Fix UploadFile ForwardRef error — remove functools.wraps from wrap_plugin_route B4: DMS upload uses true streaming via save_stream() instead of RAM accumulation B5: Worker on_startup registers plugin event handlers + webhook dispatcher B6: Implement send_password_reset_email job, remove raw token logging B7: Webhook SSRF protection (IP validation, no redirects), secret removed from response B8: RLS repair migration 0044 + separate crm_runtime DB user (NOSUPERUSER, NOBYPASSRLS) B9: Fix .env.docker.example AUTH_SECRET → SECRET_KEY B10: Remove Redis default password, remove exposed DB/Redis ports Also: add frontend_url to config, add SMTP settings to .env.docker.example, update prestart.sh to use MIGRATION_DATABASE_URL for alembic.
This commit is contained in:
+52
-2
@@ -90,11 +90,59 @@ def _get_redis_settings() -> RedisSettings:
|
||||
async def on_startup(ctx: dict[str, Any]) -> None:
|
||||
"""Called when worker starts."""
|
||||
logger.info("ARQ worker starting...")
|
||||
|
||||
# Initialize Redis singleton (same as API lifespan)
|
||||
from app.core.auth import init_redis
|
||||
await init_redis()
|
||||
|
||||
# Initialize service container
|
||||
from app.core.service_container import get_container
|
||||
container = get_container()
|
||||
await container.initialize()
|
||||
|
||||
# Initialize plugin registry and discover built-in plugins
|
||||
from app.plugins.registry import get_registry
|
||||
from app.core.db import get_engine
|
||||
from app.core.event_bus import get_event_bus
|
||||
from app.core.webhook_dispatcher import register_webhook_event_handlers
|
||||
from sqlalchemy import select as sa_select
|
||||
from app.models.plugin import Plugin as PluginModel
|
||||
from sqlalchemy.ext.asyncio import async_sessionmaker
|
||||
|
||||
registry = get_registry()
|
||||
registry.initialize(get_engine(), app=None)
|
||||
registry.discover_builtins()
|
||||
|
||||
event_bus = get_event_bus()
|
||||
async_session = async_sessionmaker(get_engine(), expire_on_commit=False)
|
||||
|
||||
# Activate plugins that are marked active in DB (register event handlers)
|
||||
async with async_session() as db:
|
||||
for name in registry.resolve_load_order():
|
||||
plugin = registry.get_plugin(name)
|
||||
if plugin is None:
|
||||
continue
|
||||
result = await db.execute(
|
||||
sa_select(PluginModel).where(PluginModel.name == name)
|
||||
)
|
||||
plugin_record = result.scalar_one_or_none()
|
||||
if plugin_record is None or not plugin_record.active:
|
||||
continue
|
||||
try:
|
||||
await plugin.on_activate(db, container, event_bus)
|
||||
logger.info(f"Worker: activated plugin {name}")
|
||||
except Exception as exc:
|
||||
logger.error(f"Worker: failed to activate plugin {name}: {exc}")
|
||||
await db.commit()
|
||||
|
||||
# Register webhook dispatcher on the event bus
|
||||
register_webhook_event_handlers(event_bus)
|
||||
logger.info("Worker: webhook event handlers registered")
|
||||
|
||||
# Register search providers (normally done by app startup)
|
||||
try:
|
||||
from app.core.db import get_session_factory
|
||||
from app.plugins.builtins.unified_search.provider_registry import auto_register_providers
|
||||
factory = get_session_factory()
|
||||
factory = async_session
|
||||
async with factory() as db:
|
||||
await auto_register_providers(db)
|
||||
logger.info("Search providers registered for worker")
|
||||
@@ -105,6 +153,8 @@ async def on_startup(ctx: dict[str, Any]) -> None:
|
||||
async def on_shutdown(ctx: dict[str, Any]) -> None:
|
||||
"""Called when worker shuts down."""
|
||||
logger.info("ARQ worker shutting down...")
|
||||
from app.core.auth import close_redis
|
||||
await close_redis()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user