Skip to content

Fix dashboard plugins using static ServiceProvider (#3026)#3035

Merged
lahma merged 3 commits into
3.xfrom
dashboard-static
Apr 11, 2026
Merged

Fix dashboard plugins using static ServiceProvider (#3026)#3035
lahma merged 3 commits into
3.xfrom
dashboard-static

Conversation

@lahma

@lahma lahma commented Apr 11, 2026

Copy link
Copy Markdown
Member

Summary

  • Replace static IServiceProvider fields in DashboardLiveEventsPlugin and DashboardHistoryPlugin with per-scheduler instance storage via SchedulerContext, fixing ObjectDisposedException when multiple hosts exist in the same process (e.g. WebApplicationFactory integration tests)
  • Wrap plugin listener callbacks in try-catch(ObjectDisposedException) so a dashboard failure never aborts Quartz's listener notification chain
  • Store the host's IServiceProvider in scheduler.Context during MapQuartzDashboard() instead of setting static fields

Fixes #3026

Test plan

  • Build succeeds with zero warnings (dotnet build src/Quartz.Dashboard/Quartz.Dashboard.csproj)
  • Verify dashboard live events and history still work in a single-host scenario
  • Verify no ObjectDisposedException when multiple WebApplicationFactory hosts run concurrently and one disposes

🤖 Generated with Claude Code

…t scenarios (#3026)

Replace static IServiceProvider fields in DashboardLiveEventsPlugin and
DashboardHistoryPlugin with per-scheduler instance storage via SchedulerContext.
This prevents ObjectDisposedException when multiple hosts exist in the same
process (e.g. WebApplicationFactory integration tests) and one host disposes.

Also wrap plugin listener callbacks in try-catch(ObjectDisposedException) so a
dashboard failure never aborts Quartz's listener notification chain.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@lahma lahma added the port-main Requires porting to main branch label Apr 11, 2026
1. Store ServiceProvider in all schedulers via GetAllSchedulers(), not
   just the default, so named schedulers also get dashboard wiring.
2. Restore public static ServiceProvider properties with [Obsolete] to
   preserve source/binary compatibility on 3.x.
3. Make BroadcastToScheduler async so the try-catch covers asynchronous
   ObjectDisposedException from SignalR send, not just synchronous throws.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@flozano

flozano commented Apr 11, 2026

Copy link
Copy Markdown

I didn't even start it, and it's done :D thank you!

1. Store IServiceProvider in SchedulerContext from
   ServiceCollectionSchedulerFactory.InitializeScheduler instead of
   MapQuartzDashboardCore. This keeps dashboard mapping passive (no
   eager scheduler creation) and handles scheduler recreation since
   InitializeScheduler runs for every new/replacement scheduler.
2. Fall back to the obsolete static ServiceProvider property when the
   context entry is absent, so external consumers that set the property
   directly still get working behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@sonarqubecloud

Copy link
Copy Markdown

@lahma
lahma merged commit 535ed75 into 3.x Apr 11, 2026
16 checks passed
@lahma
lahma deleted the dashboard-static branch April 11, 2026 08:11
@lahma lahma removed the port-main Requires porting to main branch label Apr 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants