Fix runtime issues found during live testing
Some checks failed
Validate / Hassfest (push) Has been cancelled

- Fix jinja2.sandbox import: use `from jinja2.sandbox import
  SandboxedEnvironment` (dotted attribute access doesn't work)
  in templates.py, sync.py, and notifier.py
- Fix greenlet crash in tracker trigger: SQLAlchemy async sessions
  can't survive across aiohttp.ClientSession context managers.
  Eagerly load all tracker/server data before entering HTTP context.
  Split check_tracker into check_tracker (scheduler, own session)
  and check_tracker_with_session (API, reuses route session).
- Fix _check_album to accept pre-loaded params instead of tracker
  object (avoids lazy-load access after greenlet context break)

Tested end-to-end against live Immich server:
- Server connection + album browsing: OK (39 albums)
- Template creation + preview: OK
- Webhook target creation: OK
- Tracker creation + trigger: OK (initialized 4 assets)
- Second trigger: OK (no_changes detected)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 15:17:12 +03:00
parent 62bf15dce3
commit 3a516d6d58
6 changed files with 60 additions and 34 deletions

View File

@@ -6,6 +6,7 @@ from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession
import jinja2
from jinja2.sandbox import SandboxedEnvironment
from ..database.engine import get_session
from ..database.models import (
@@ -136,7 +137,7 @@ async def render_template(
raise HTTPException(status_code=404, detail="Template not found")
try:
env = jinja2.sandbox.SandboxedEnvironment(autoescape=False)
env = SandboxedEnvironment(autoescape=False)
tmpl = env.from_string(template.body)
rendered = tmpl.render(**body.context)
return {"rendered": rendered}

View File

@@ -6,6 +6,7 @@ from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession
import jinja2
from jinja2.sandbox import SandboxedEnvironment
from ..auth.dependencies import get_current_user
from ..database.engine import get_session
@@ -124,7 +125,7 @@ async def preview_template(
"""Render a template with sample data."""
template = await _get_user_template(session, template_id, user.id)
try:
env = jinja2.sandbox.SandboxedEnvironment(autoescape=False)
env = SandboxedEnvironment(autoescape=False)
tmpl = env.from_string(template.body)
rendered = tmpl.render(**_SAMPLE_CONTEXT)
return {"rendered": rendered}

View File

@@ -128,9 +128,8 @@ async def trigger_tracker(
):
"""Force an immediate check for a tracker."""
tracker = await _get_user_tracker(session, tracker_id, user.id)
# Import here to avoid circular imports
from ..services.watcher import check_tracker
result = await check_tracker(tracker.id)
from ..services.watcher import check_tracker_with_session
result = await check_tracker_with_session(tracker.id, session)
return {"triggered": True, "result": result}