feat(vector-sync): scan provisioned users immediately

Background vector sync discovered newly provisioned users only on the
periodic user-manager poll (VECTOR_SYNC_USER_POLL_INTERVAL, default 60s),
delaying first indexing by up to a minute. Add a ProvisionSignal doorbell
that provisioning paths ring after storing a user's app password, waking
user_manager_task to re-poll and spawn the user's scanner at once. The
periodic poll remains the backstop (covers cross-replica provisioning).

- ProvisionSignal (stable reference, wait-and-re-arm) held on
  VectorSyncState; closes the lost-wakeup window (no await between observing
  the ring and re-arming; anyio.Event stickiness covers a mid-poll ring)
- user_manager_task races its poll timeout against the doorbell + shutdown
- notify_user_provisioned() rung from the three app-password provisioning
  sites: Login Flow v2 web, MCP provisioning tool, management/BasicAuth API

Note: the pre-existing scanner_wake_event was never .set() and only wakes
existing scanners; a brand-new user has none, so the manager is what must
be nudged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-12 09:48:56 +02:00
co-authored by Claude Opus 4.8
parent 4688f2f95a
commit d8e3e9bc33
7 changed files with 503 additions and 2 deletions
+6
View File
@@ -407,6 +407,12 @@ async def provision_app_password(request: Request) -> JSONResponse:
username, app_password, scopes=scopes, username=nc_username
)
invalidate_scope_cache(username)
# Wake the background sync user manager so this user's scanner starts
# now instead of after the next poll. Local import avoids an app <->
# api-module import cycle.
from nextcloud_mcp_server.app import notify_user_provisioned # noqa: PLC0415
notify_user_provisioned()
_record_rate_limit_attempt(path_user_id, success=True)
logger.info("Provisioned app password for user: %s", username)