Trim and AOT compatibility track — what remains
The eight-step sequence this issue opened with is done. Quartz sets IsTrimmable,
IsAotCompatible, and the trim, AOT and single-file analyzers, with
TreatWarningsAsErrors; ObjectUtils is gone and the fire path carries
[DynamicallyAccessedMembers] end to end; the HTTP wire contract, the store's JSON blobs and the
Quartz configuration section are all source-generated; and Quartz.Trimming.Canary is published
natively and run on Windows, Linux and macOS on every pull request, scheduling and firing
over a real SQLite store and binding a whole scheduler out of an IConfiguration. Quartz produces
no IL3050 at all. Quartz.Jobs, Quartz.Plugins, Quartz.HttpClient, Quartz.AspNetCore,
Quartz.Extensions.Redis and Quartz.Plugins.TimeZoneConverter are marked trimmable and carry
their own baselines; Quartz.Serialization.Newtonsoft and Quartz.Dashboard say the opposite,
deliberately.
What is left is 23 recorded IL2xxx entries over 14 types, in
src/Quartz/TrimAnalysisBaseline.cs (18 over 11 types), src/Quartz/ILLink.Suppressions.xml (one
more that only ILLink sees), and the four package baselines. They are three shapes, and none of
them is a bug:
- A string names a type — flat
quartz.*keys,JOB_CLASS_NAME, a driver name, a plugin or listener type name, a job named inquartz_jobs.json. Every public API that takes such a string already says[RequiresUnreferencedCode]. What is recorded is Quartz reading its own configuration and its own tables, on paths reachable fromAddQuartzor across an interface Quartz does not own both sides of. - A value coerced onto a property the compiler cannot see —
Quartz.Util.ValueConverter. The target arrives asPropertyInfo.PropertyType, which the framework does not annotate and could not, so there is no chain to build. - Duck-typed provider errors —
TransientErrorDetectorreadsSqlException.NumberandSqliteException.SqliteErrorCodeoff types Quartz deliberately does not reference.
Closing any of these means deleting a feature, not writing an annotation. This issue stays open as
the standing record the two baseline files point at, and as the rule they enforce: a warning
against a type not listed there means new reflection — fix it rather than adding a line.
TrimAnalysisBaseline.cs gives the order to try the fixes in.
Open, and genuinely open:
- A job-data value of an application's own type in a reflection-off publish. Answered by
SystemTextJsonSerializerRegistry.AddTypeInfoResolver; the open registry is deliberately not source-generated. Documented indocs/documentation/quartz-4.x/how-tos/trimming-and-native-aot.md. The remaining work is ergonomics, not correctness. Quartz.Serialization.NewtonsoftandQuartz.Dashboardwill not become trimmable. Json.NET's contract is reflection and Blazor Server binds components by name. Recorded, not tracked.
Source: quartznet/quartznet