Skip to content

Schedule plugin background tasks with TickerQ - #276

Merged
PianoNic merged 2 commits into
mainfrom
feature/233_TickerQScheduler
Sep 9, 2026
Merged

PianoNic merged 2 commits into
mainfrom
feature/233_TickerQScheduler

Conversation

@PianoNic

@PianoNic PianoNic commented Sep 9, 2026

Copy link
Copy Markdown
Member

Summary

  • Replaced the hand-rolled plugin task loop (PluginHost.RunTaskLoop plus the in-memory PluginSchedulerRegistry) with TickerQ, persisted to SchulyDbContext through the EF Core operational store. Schedules, next-run times and run history now survive a restart, cron replaces drifting intervals, and failed runs retry per the plugin's declared policy.
  • Resolved the source-generator vs runtime-plugin problem the issue calls out: TickerQ discovers ticker functions with a compile-time source generator, so a [TickerFunction] inside a plugin assembly loaded into a collectible AssemblyLoadContext could never be seen. The host instead owns a single [TickerFunction("RunPluginTask")] that carries { plugin, task } and dispatches into the plugin's own DI scope by name. Plugins never reference TickerQ.
  • On load, each IPluginBackgroundTask is upserted as a cron ticker keyed "<plugin>/<task>", so a reload updates rather than duplicates and a task dropped by a plugin update stops firing; unload withdraws the plugin's tickers and drains in-flight runs before the plugin provider is disposed. RunOnStartup adds a one-shot time ticker.
  • Operators can override a task's cadence per deployment in plugins-config/<AssemblyName>.yml under Schedules:<task>:{Cron,Retries,RunOnStartup}; an override that fails validation is ignored in favour of the plugin default rather than taking the task offline.
  • GET /api/plugins/scheduler keeps its response shape, now backed by TickerQ's persisted cron tickers and occurrences (last run, next run, last status, failure counts). The TickerQ dashboard is mounted at /tickerq in Development only.
  • Each run now executes in a fresh scope on the plugin's provider instead of the plugin root provider, so a scoped SchulyDbContext no longer lives for the process lifetime.
  • Migration AddTickerQ creates the ticker schema. Docs updated; PluginBackgroundTaskHost references in docs/architecture.md were stale and now describe the real runtime.

Depends on schulydev/SchulyPluginAbstractions#144, which replaces IPluginBackgroundTask.Interval with PluginSchedule. Version 0.3.0 is not published to nuget.org yet, so CI will fail to restore Schuly.Plugin.Abstractions 0.3.* until that release is cut. It was verified locally against a 0.3.0 pack: dotnet build clean with 0 warnings, dotnet test 52/52 green.

The .gitignore change is not incidental: /src/Schuly.API/plugins/ matched the tracked src/Schuly.API/Plugins/ sources on case-insensitive checkouts, so new files in the plugin runtime folder were silently ignored. The runtime drop folder is now matched by artifact extension instead.

Follow-up, deliberately not in this PR: a host service that lets a plugin trigger a one-shot run of one of its own tasks ("sync this account now") would need a new cross-boundary interface in the abstractions package. The existing on-demand sync mechanism is unchanged here.

Closes #233

@PianoNic PianoNic added the refactor Code refactor label Sep 9, 2026
…heduler

# Conflicts:
#	src/Schuly.API/Plugins/PluginHost.cs
#	src/Schuly.API/Program.cs
#	src/Schuly.Infrastructure/Migrations/SchulyDbContextModelSnapshot.cs
#	src/Schuly.Tests.Plugin/TestPlugin.cs
#	src/Schuly.Tests/PluginHotSwapTests.cs
#	src/Schuly.Tests/TestHelpers/PluginTestHarness.cs
@PianoNic
PianoNic merged commit 6cc8e12 into main Sep 9, 2026
1 check passed
@PianoNic
PianoNic deleted the feature/233_TickerQScheduler branch September 9, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace the hand-rolled plugin task scheduler with TickerQ

1 participant