Skip to content

feat: add Sentry.Quartz for cron monitoring of Quartz.NET 4.x jobs - #5674

Closed
wedamija wants to merge 38 commits into
mainfrom
danf/quartz4-crons
Closed

wedamija wants to merge 38 commits into
mainfrom
danf/quartz4-crons

Conversation

@wedamija

@wedamija wedamija commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Description

Builds on #5505 by @michaelmairegger.

Adds Sentry.Quartz, a Quartz.NET 4.x integration built on job middleware. Each job runs in its own Sentry scope and trace, tagged with its job key, and what it throws is captured in that scope. Jobs with [SentryCronMonitorSlug] also send a check-in for each run: in-progress when it starts, then ok or error with the duration.

services.AddQuartz(q => q.AddSentry());

[SentryCronMonitorSlug] // or [SentryCronMonitorSlug("nightly-report")]
public class NightlyReport : IJob { ... }

Jobs without the attribute aren't monitored. The slug is the attribute's value, else the slugified job key (reports.DailyEmail → reports-dailyemail), so job keys that share a class don't share a monitor. SentryMonitorSlug in the job or trigger data map overrides it.

For opted-in jobs, the trigger's schedule is sent as the monitor config by default. [SentryCronMonitorSlug(SendMonitorConfig = false)] turns it off for one job, SentryQuartzOptions.SendMonitorConfig for all. Cron triggers are sent only when Sentry reads the expression the same way (Quartz has seconds and year fields and numbers weekdays from 1 = SUN), and simple triggers only when they repeat forever at whole minutes, hours or days. Schedules that can't be represented exactly (calendars, L/W/#, several triggers sharing a monitor) get check-ins without a config, rather than a schedule that would cause false missed-check-in alerts. ConfigureMonitorOptions sets per-job thresholds and can override the schedule.

The schedule, slug and check-in code is in src/Sentry.Quartz/Core/ so the Quartz 3 package (#5668) compiles the same files. SentryMonitorOptions gets an internal HasSchedule so the callback can replace the trigger's schedule.

A release-registry entry is needed before the first release.

Motivation

Check-ins for a monitor that doesn't exist yet are dropped, so each monitor would have to be created by hand with its schedule copied from the trigger. The trigger already has the schedule, so the SDK can send it and monitors are created and kept in sync automatically.

Changes from #5505

  • One AddSentry() replaces AddSentryCronJobs() and AddSentryScope(). The class is SentryQuartzBuilderExtensions, since Quartz has its own QuartzBuilderExtensions in the Quartz namespace.
  • The middleware uses HubAdapter and IDiagnosticLogger, so nothing needs to be registered in DI. Strong naming is back on.
  • Fixed the day-of-week shift, the dropped year field, the uncaught FormatException and the per-class slugs. Calendars, several triggers and simple triggers are handled.
  • Removed the leftover metrics middleware references that broke the build.

Testing

Tests for the schedule conversion, slugs and options, both middleware, and a real in-memory scheduler set up with AddSentry(). API approval file added. The sample is samples/Sentry.Samples.Quartz.

Docs: getsentry/sentry-docs#19790

michaelmairegger and others added 30 commits October 6, 2025 11:02
… dependencies and streamlining SentryCronJobListener options handling
# Conflicts:
#	.generated.NoMobile.sln
#	Sentry.sln
… collection parameter and streamlining option configuration
…dSentryScope method, update SentryMetricsMiddleware to support configurable options
The format-code workflow can't push its auto-fix to a fork branch, so it
fails the check instead. Applying the fix here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every package needs a name/packageUrl/mainDocsUrl entry so craft can create
its registry entry on first publish; a missing `name` fails the whole
registry target rather than just that package.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.32258% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.26%. Comparing base (5ddcf4d) to head (a5da5cf).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/Sentry.Quartz/Core/JobMonitor.cs 86.58% 3 Missing and 8 partials ⚠️
src/Sentry.Quartz/Core/TriggerSchedule.cs 92.30% 3 Missing and 4 partials ⚠️
src/Sentry.Quartz/SentryQuartzBuilderExtensions.cs 50.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5674      +/-   ##
==========================================
+ Coverage   74.94%   75.26%   +0.32%     
==========================================
  Files         515      523       +8     
  Lines       18975    19192     +217     
  Branches     3695     3755      +60     
==========================================
+ Hits        14220    14445     +225     
+ Misses       3875     3844      -31     
- Partials      880      903      +23     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

wedamija and others added 2 commits October 5, 2026 18:46
Keeps the middleware design from #5505 and adds what the cron monitors
need on top:

- One AddSentry() entry point on IQuartzBuilder that registers the scope
  and check-in middleware with HubAdapter, so no IHub is needed in DI.
- The scope middleware starts a new trace per run and captures what the
  job throws inside the run's scope.
- Check-ins only for jobs with [SentryCronMonitorSlug]. The slug comes
  from the trigger or job data map, the attribute, or the slugified job
  key, so job keys sharing a class don't share a monitor.
- The monitor config is converted from cron and simple triggers, with
  the Quartz day-of-week shift, and left out when Sentry can't represent
  the schedule. SendMonitorConfig turns it off globally or per job.
- ConfigureMonitorOptions runs before the trigger's schedule is applied,
  so it can override it, and never breaks the check-in.
- The package is signed and restricted to Quartz [4.0.0,5.0.0).

The schedule conversion, slug and check-in logic live in Core/ so the
Quartz 3 package can compile the same files.

Co-Authored-By: Claude <noreply@anthropic.com>
@wedamija
wedamija force-pushed the danf/quartz4-crons branch from 7d4739c to 926ee05 Compare October 6, 2026 02:03
@wedamija
wedamija changed the base branch from danf/quartz-crons to main October 6, 2026 02:03
@michaelmairegger

Copy link
Copy Markdown
Contributor

@wedamija i suggest to rename the quartz4 package to ghe generic name Sentry.Quartz, not Sentry.Quartz.4

Sentry.Quartz v3 has incompatible code parts. So this name is fine.

Sentry.Quartz3 keeps its name for Quartz.NET 3.x.

Co-Authored-By: Claude <noreply@anthropic.com>
@wedamija wedamija changed the title feat: add Sentry.Quartz4 for cron monitoring of Quartz.NET 4.x jobs feat: add Sentry.Quartz for cron monitoring of Quartz.NET 4.x jobs Oct 6, 2026
@wedamija wedamija closed this Oct 13, 2026
@wedamija
wedamija deleted the danf/quartz4-crons branch October 22, 2026 17:02
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.

3 participants