Bump Marten and 5 others - #212
Closed
dependabot[bot] wants to merge 1 commit into
Closed
dependabot[bot] wants to merge 1 commit into
dependabot[bot] wants to merge 1 commit into
Conversation
Bumps Marten from 9.30.0 to 9.33.0 Bumps Quartz.Extensions.Hosting from 3.20.0 to 3.21.0 Bumps Quartz.Serialization.SystemTextJson from 3.20.0 to 3.21.0 Bumps Radzen.Blazor from 11.2.8 to 11.3.2 Bumps WolverineFx.Marten from 6.32.0 to 6.36.0 Bumps WolverineFx.RuntimeCompilation from 6.32.0 to 6.36.0 --- updated-dependencies: - dependency-name: Marten dependency-version: 9.33.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: Quartz.Extensions.Hosting dependency-version: 3.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: Quartz.Serialization.SystemTextJson dependency-version: 3.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: Radzen.Blazor dependency-version: 11.3.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.Marten dependency-version: 6.36.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch - dependency-name: WolverineFx.RuntimeCompilation dependency-version: 6.36.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This was referenced Sep 12, 2026
Contributor
Author
|
Looks like these dependencies are updatable in another way, so this is no longer needed. |
dependabot
Bot
deleted the
dependabot/nuget/nuget-minor-patch-f8902eea98
branch
September 19, 2026 02:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pinned Marten at 9.33.0.
Release notes
Sourced from Marten's releases.
9.33.0
The concurrency and portability release: a shared-state race that broke parallel
db-apply, a Native AOT query failure, and two cross-store divergences settled in Marten's favour and against it respectively.Dependencies move to JasperFx 2.67.0 and Weasel 9.31.1.
db-apply --parallelcould die with "Collection was modified" (#5364)Applying schema changes to many databases concurrently intermittently failed on one of them with:
Reported from a production deployment at 29 databases and
--parallel 16, where it hit exactly one database per run.One
ManagedListPartitionsinstance is shared by every database in a store. It mutated its partition dictionary in place and published it through aReadOnlyDictionary— which wraps rather than copies — soInitializeAsync'sClear()-and-refill ran while another database's worker was mid-enumeration. Fixed upstream in Weasel 9.31.1 (JasperFx/weasel#583) by publishing the registry as a snapshot swapped copy-on-write. Marten needs only the bump; there is no Marten code change.Two things worth knowing if you hit this before upgrading:
The same Weasel fix covers
Weasel.SqlServer'sManagedTenantPartitions, which had the identical shape.An enum compared to a captured variable failed under Native AOT (#5361)
where x.Status == capturedthrewBadLinqExpressionExceptionwrappingPlatformNotSupportedException: Dynamic code generation is not supported on this platform, while the same comparison against a literal worked. C# lowers enum equality to a comparison of the underlying integers, so the value side always arrives asConvert(closure.captured, Int32)— a shape 9.32.1's reflective walk did not cover, which sent it to FastExpressionCompiler and therefore toReflection.Emit.Two changes, because the enum shape was the symptom rather than the cause. The reflective walk now handles conversions between an enum and anything sharing its integral representation, including the
Nullable<T>forms — widening and narrowing are still left alone, so no value is ever reinterpreted. AndReduceToConstantno longer requires the ability to emit at all: where the platform cannot, shapes the walk declines fall back to the BCL expression interpreter instead of throwing. Without that second half, every expression shape Marten has not explicitly been taught was a latent AOT failure.EventQuery.TagValuesis now honored (#5365)The lossy name/value tag filter, on the composable query object. Previously you filtered by tags or by everything else: the dictionary form existed only on the non-composable
QueryByTagsAsync, which is unpaged and has noTotalCount. Now a caller holding a tag name can AND it with the event type, window, stream, metadata and tenant filters and keep paging and a truthful total.Note the semantics, which differ from the rich
TagConditionsform deliberately: entries AND (an event must carry every named tag at the given value), whereTagConditionsconditions OR. Supplying both spellings on one query is refused rather than resolved by a silent precedence rule.Behaviour change: dictionary tag queries accept either spelling, case-insensitively
Fixing the above exposed a divergence in the existing
IEventStore.QueryByTagsAsync(IReadOnlyDictionary<string,string>, …)overload. It matched a tag name against the CLR type name only and compared the value case-sensitively, while Polecat accepted either spelling and compared case-insensitively — so the same dictionary answered differently depending on which store you asked, and guessing wrong was anArgumentExceptionat runtime.Both that overload and the new
TagValuespath now resolve names through the shared matcher (CLR simple name or registered table suffix, case-insensitively) and compare values against the string form of the stored tag value, ordinal case-insensitively. Postgres renders a Guid lowercase through::textwhile SQL Server renders it uppercase, so an operator's copy-pasted id no longer depends on which store answered.If you relied on a tag name or value being matched case-sensitively, this query now matches more rows than it used to. An unregistered tag name is still an
ArgumentExceptionlisting what is registered, never an empty answer.CompactStreamAsync<T>infers the fold for an unregistered aggregate (#5366)Compaction refused any type without a registered aggregation projection, while Fisher and Polecat both inferred one. That made a compaction policy able to target only an aggregate the application already snapshots — a real constraint on the feature, invisible until runtime, and one nobody would infer from the API.
CompactStreamAsync<T>now builds the aggregator fromT's ownCreate/Applyconventions when no projection is registered, which is what every other aggregation path in Marten already did. The typed overload namesToutright, and that is the same declaration of intent a registration would be.... (truncated)
9.32.1
A bug-fix release, on JasperFx 2.66.0 and Weasel 9.31.0. The headline is that Native AOT document reads worked for nobody before this; the rest is correctness work on natural keys, the outbox, EF Core projections, and flat tables.
Several of these change observable behaviour. Each one is called out below.
Native AOT: reading a document from a native binary (#5328)
An app published with
PublishAot=truebuilt and published analyzer-clean, then threw on the first document read. Writes — including schema creation — were fine. Three separate sites, all on the read path:QuerySession.StorageFor(Type)andCompiledQueryPlan.sortMembers()both went from a runtimeTypeback to a closed generic throughMakeGenericType+Activator.CreateInstance, and ILC has no native code for an instantiation nothing constructs statically. The third — expression compilation for every non-literal value in awhereclause, i.e. everywhere x.Member == captured— is Reflection.Emit, which native AOT does not have at all.All three now capture the closed generic where the compiler has already emitted it.
LoadAsync, LINQ, raw SQL,Include, patching and source-generated compiled queries all run from a native binary.Two shapes still need a JIT, and both have a one-line workaround (documented in the AOT publishing guide): a compiled query with an
enum-typed parameter, and awhereclause whose value comes from a method call — hoist the call into a local first.Marten also ships a new runtime gate,
src/Marten.AotRuntimeSmoke, which publishes natively and runs every read path against a real PostgreSQL in CI. The existingMarten.AotSmokeis a build-time analyzer gate and was structurally blind to this class of defect: the offending code analyzes clean and throws one line later. If you publish AOT, do the same in your own pipeline — a clean publish is necessary, not sufficient.Natural keys: three fixes, two of them behavioural (#5344)
The first run of the shared
NaturalKeyCompliancesuite against Marten found three genuine bugs in the[NaturalKey]lookup table.A
[NaturalKey]of primitive typestringon a Guid-identity store now works.FindFetchPlanasserted string stream storage for anystringTId and refused with "This Marten event store is configured to identify streams with Guids" before any planner saw it. Both that guard and its mirror image inNaturalKeyFetchPlannernow narrow to the store's own stream identity type. The ambiguous case is unchanged by design: on a string-identity store,FetchLatest<T, string>(value)still addresses the stream.A failed unit of work no longer commits its outbox batch (#5353)
IMessageBatch.BeforeCommitAsyncwas called before theUpdateBatchwas built and before a transaction was even open — so it fired for units of work that had not been attempted, let alone succeeded. ASaveChangesAsyncthat then failed (a stream-id collision, say) left the message batch enlisted and committed, with no rollback hook able to un-enlist it.The batch is now enlisted as an
ITransactionParticipant, invoked inside the transaction after every page has executed and immediately before theCOMMIT. A unit of work that fails never reaches it. Hook ordering and the inside/outside-the-transaction visibility contract are unchanged; the before hook simply runs later in the transaction. This is the placement Polecat already used.EF Core projections stop generating a Marten document table (#5351, #5329)
Registering an
EfCoreSingleStreamProjection/EfCoreMultiStreamProjectionmade Marten build aDocumentMappingfor the aggregate type and emit schema for it, even though EF Core owns that data in aDbContext-mapped table Marten never reads or writes. Two consequences, both fixed:ApplyAllConfiguredChangesToDatabaseAsync()created an emptymt_doc_<tdoc>table nothing used — and in the normalAutoCreate.Noneshape, where schema is built by a migration pass that does not register the projection,AssertDatabaseMatchesConfigurationAsync()then reported that table as MISSING and a correctly-migrated database failed its own startup assertion.... (truncated)
9.32.0
Two coordinated feature waves against JasperFx.Events 2.63.0, plus the compliance enrollments that keep Marten, Polecat, and Fisher synchronized.
Broadened event querying (jasperfx#737 → #5330 / #5331)
QueryEventsAsync/EventQuerynow supports inclusive timestamp windows (TimestampFrom/TimestampTo), inclusive sequence windows (SequenceFloor/SequenceCeiling), multiple event type aliases (EventTypeNames, union with the singleEventTypeName), and DCB tag conditions folded into the query (TagConditions— the TagTables and HStore modes both translate through the same SQL asQueryByTagsAsync). Results are contractually ordered sequence-ascending;TotalCountcounts matches across all pages.Stream state querying + the compaction watermark (jasperfx#740 → #5333 / #5334)
QueryStreamStates(tenantId?)exposes a realIQueryable<StreamState>overmt_streams— every public member translates inWhere(), includingAggregateType == typeof(X)(resolved through the stored type alias) and the newCompactedVersionwatermark, so a compaction policy predicate likes.AggregateType == typeof(Order) && s.Version - s.CompactedVersion > 1000 && !s.IsArchivedruns server-side.mt_streamsgains an additivecompacted_version bigint NOT NULL DEFAULT 0column (Weasel migration; expect a one-time schema-touch burst on a first local test run against pre-existing schemas), andCompactStreamAsyncrecords the watermark in the same unit of work — monotonically (greatest()), so a replayed lower-cutoff compaction can never move it backwards. Untranslatable members and a tenant scope on a non-conjoined store refuse by name, never silently match-all.CLI + compliance
The JasperFx.Events
event-queryandstream-querycommands are covered end-to-end against Marten (first CLI-execution tests in the repo). Compliance:EventQueryCompliance(41 facts) andStreamStateQueryCompliance(15) enrolled; the full compliance namespace runs 388/388 on net9.0 and net10.0.Note for code importing both
MartenandJasperFx.Events.Documents: extension-styleToListAsyncover the stream queryable is ambiguous (CS0121) — call the JasperFx extensions explicitly.🤖 Generated with Claude Code
9.31.2
A diagnostics-only patch release. No behavioural change to the write path.
A failed batched write now reports the SQL that failed
When a batched write failed, Marten threw a
MartenCommandExceptionwhose message rendered an empty command text. Reported from the field on an async projection:The
$ $ $is the message template interpolating a command that was always null.ReadNpgsqlCommand()looks for anNpgsqlCommandinexception.Data, and on theExecuteBatchPagesAsyncpath there is no single command to put there —AutoClosingLifetimetransformed the exception with nothing recorded at all, andWrapAndThrow(NpgsqlBatch, ...)recorded the batch under a key that nothing ever read.The practical consequence: the offending SQL was unrecoverable from the exception and from the logs, for every async projection write. That is precisely the situation where hand-written SQL — a
QueueSqlCommand, a customIStorageOperation, a projection side effect — turns out to be malformed, and the one thing you need to see is the statement.MartenCommandExceptionnow recovers the SQL from three sources, in order:NpgsqlCommandit was handed;NpgsqlException.BatchCommand— Npgsql identifies the exact statement the server rejected when the failure came out of a batch execution;NpgsqlBatchrecorded on the exception.The recovered statement is also exposed on a new
MartenCommandException.CommandTextproperty, so it can be read programmatically rather than scraped out of the message.AutoClosingLifetimeexecutes its batches inline rather than throughhandleCommandException, so it now records its batch. The other three connection lifetimes already routed throughWrapAndThrow(NpgsqlBatch, ...)and only needed a reader for the key they were already writing.Two guardrails worth knowing about: a batch renders at most five statements, so a 500-operation projection page cannot turn one failure into an unreadable log entry, and the whole resolution is wrapped in a
catch— building a diagnostic must never replace the real failure.Also released as 8.38.1 on the 8.x line.
9.31.1
A single-fix patch release that moves Marten to JasperFx 2.61.0, picking up the source generator fix for JasperFx/jasperfx#733. Weasel stays on 9.29.0.
Self-aggregating snapshots silently skipped a constructor-based
CreateA self-aggregating snapshot may declare its Create handler as an event-shaped constructor,
public Foo(FooCreated e), instead of a namedstatic Create. That works on its own. Adding aShouldDeletemethod to the same aggregate switched the source generator to a different emitter — one that built its dispatch switch from named conventional methods only — so the constructor's event type got no case arm at all.Nothing failed loudly. The generated code compiled, the constructor never ran, and the next Apply-only event built the aggregate through
RuntimeHelpers.GetUninitializedObject, skipping every field initializer. The visible symptom was anApplyEventExceptionwrapping aNullReferenceExceptionout of anApplythat appended to a collection property:The quieter outcome, where no
Applyhappens to dereference anything, is a silently blank aggregate.Both documented workarounds — converting the constructor to a
static Create, or registering the delete throughDeleteEvent<T>()instead ofShouldDelete— become unnecessary on this release.The same omission was also in the generated
EventTypesproperty on every self-aggregating path, including the ones whose dispatch was already correct, so an aggregate with a constructorCreateand noShouldDeletegains its creating event in that list here too.Covered by
Bug_jasperfx_733_event_constructor_create_with_should_deleteacross inline, async and live aggregation, plus the delete arm itself. See #5322.9.31.0
Every fix in this release removes a silent wrong answer — not a crash, not an exception, but a plausible-looking result that was wrong with nothing to tell you so. A stream folded into partial aggregates. Paging that returned arbitrary pages. Monitoring that went dark rather than broken. A search reading a key that did not exist. An index that was never created.
Plus one genuinely new feature: weighted full text search with relevance ranking.
New: weighted full text indexes and
ts_rankorderingA full text index used to concatenate its members into one flat vector, so a match in a title was exactly as relevant as a match in a long description. Now it can be weighted, and ranked:
The rank resolves the same tsvector the
Whereclause matched on, read from the index definition. That is the load-bearing design constraint rather than an implementation detail: a rank computed over a different vector than the filter matched on returns rows in an order that looks plausible and means nothing — a far quieter failure than returning the wrong rows.Requires Weasel 9.29.0 (weasel#541), which made it possible to index an expression that is already a
tsvector. See the full text documentation for the costs worth knowing first — GIN cannot order, so this is a post-filter sort; and adding weights to an existing index drops and recreates it.Silent wrong answers, fixed
Async projections folded one stream into several partial aggregates (#5305, originally #4085). When a stream's events disagreed about
tenant_id, the daemon sliced it per tenant and applied the pieces over each other, so anApplysaw a document with every property at its default. Marten had setForceSingleTenancysince the original fix, butTenantedEventSlicerhonoured that flag on only one of its two overloads — and the async daemon reaches the other one. The flag was being set on precisely the path that could not read it. Fixed upstream in JasperFx 2.58.0.OrderByafter aGroupJoin/SelectManywas dropped from the SQL (#5311). Silently, and withSkip/Takeit was worse:OFFSETandLIMITwere emitted while the ordering was not, and unordered paging in PostgreSQL has no stable row order — so rows repeat across pages while others never appear.Whereon a bare-side selector andCountover a join were wrong in the same surface and are fixed too.A store with monitoring off dropped the monitoring columns another store had added (#5309). Two
DocumentStores over oneDatabaseSchemaNamethat disagreed aboutEnableExtendedProgressionTrackingkept stripping each other'smt_event_progressioncolumns — last writer wins, silent on both sides. A service beside a seeder or a reporting job is an ordinary arrangement, and neither was doing anything wrong. The shape of that table no longer depends on configuration at all.Full text search rewrote JSON keys, not just the column (#5314, thanks @mlh758). A member whose serialized name contained
dataproducedd.data ->> 'd.data'— a key that does not exist. Two quiet consequences: that member contributed nothing to the search, and the expression no longer matched the index, so the GIN index could not serve the query either.A second full text index over different members was silently discarded (#5315). Index names derive from the table rather than from the members, so two
FullTextIndex()calls collided by construction and the second was thrown away — never registered, never created, never searched. Ambiguity is now refused with an explanatory exception instead of resolved by declaration order.A DCB boundary aggregate failed far from its cause (JasperFx 2.60.0). An identity-less
[BoundaryAggregate]folded byEvolve(IEvent)got no evolver and no diagnostic, surfacing much later asFetchForWritingByTags<T>throwing "No source-generated dispatcher found" — naming neither the type nor the reason. Now it generates, and a[BoundaryAggregate]with nothing to fold events with is reported asJFXEVT007.A DCB tag version was captured after the events were read (#5300). Two batched statements do not share a
READ COMMITTEDsnapshot, so the version could reflect a concurrent append. Captured before the read now.Also in this release
projection-runCLI command arrives with JasperFx 2.60.0 and needs no Marten change — every host referencingJasperFx.Eventspicks it up. It replays one projection over a stream slice or DCB tag match and prints per-event before/after state, writing nothing.Bug_5268's concurrent index test no longer depends on how much unrelated transaction load happens to be in flight (#5308), so validating a dependency bump by running the whole suite at once is trustworthy again.BuildSlicernow agrees withFetchAsyncPlanabout global aggregates (#5307). Alignment rather than a fix — no reachable corruption depended on it, and the reasoning is written down at the call site so the question does not have to be reconstructed next time.Upgrade notes
OrderByFragment.Expressionschanged fromList<string>toList<ISqlFragment>. A public API break, deliberately taken: an ordering could not carry a parameter while the clause was a list of strings, which is why the older ngram ranking inlines its search term rather than binding it. Nothing outside Marten's own LINQ internals is likely to touch this type, but it is a compile break if you did.... (truncated)
Commits viewable in compare view.
Pinned Quartz.Extensions.Hosting at 3.21.0.
Release notes
Sourced from Quartz.Extensions.Hosting's releases.
3.21.0
Quartz.NET 3.21.0 carries the three fixes held back from 3.20.1 because each needed a small addition to the public surface or changed what a running scheduler does. All three were found while 4.0 was being finished; each is as old as 3.x. The public API grows by two interfaces on one class and nothing else; the schema is 3.20's. Three of the changes alter behaviour, each marked Behavior change worth noting below.
What changed
ResumeAllclears every paused trigger group, not only the ones with triggers — the persistent store resumed the groups it found inQRTZ_TRIGGERSand then deleted only its all-groups marker, so a group paused while it held no triggers kept itsQRTZ_PAUSED_TRIGGER_GRPSrow and went on pausing whatever was scheduled into it afterwards. Pausing a group before anything is scheduled into it is a documented use of the exact-name matcher, so this was a row the store wrote on purpose and could not take back. The trailing delete now takes every group, asRAMJobStorehas always done. (#3721, #3742, port of f76b04a468)ResumeAll.RedisSemaphoreopened aConnectionMultiplexeron the first lock and kept it, with its heartbeat, for the life of the process, because nothing on the store's shutdown path reached the lock handler andISemaphorehad no member that meant "we are done". On a branch that targetsnetstandard2.0andnet462an interface cannot gain a default member, soJobStoreSupport.Shutdownnow disposes a lock handler that implementsIAsyncDisposableorIDisposable, after the misfire handler, the cluster manager and the connection manager have stopped, logging and continuing if that throws;RedisSemaphoreimplements both and closes the multiplexer it opened. (#3721, #3742, port of #3639)ISemaphorethat implements either interface is now disposed at shutdown.Task.Delayrefuses anything longer than about 49.7 days on .NET and about 24.9 days on .NET Framework, with anArgumentOutOfRangeExceptionnaming a parameter calleddelay, and every duration Quartz waits out that way was accepted unchecked and reported later from wherever the wait happened.MisfireHandlerFrequency,MisfireThreshold(when it is also the handler's sleep),ClusterCheckinInterval,DbRetryInterval,TransientRetryInterval, the row-lock handlers'RetryPeriod,StartDelayed's argument andQuartzHostedServiceOptions.StartDelaynow name the setting, the ceiling and the value at configuration time. The ceiling is per target framework, held to whatTask.Delayactually accepts by a test. (#3721, #3742, port of #3577)Public API — additive only
Quartz.Extensions.Redis:RedisSemaphoreimplementsIAsyncDisposableandIDisposable.Upgrading
dotnet add package Quartz --version 3.21.0. Nothing to migrate. The 4.0 line is the current major; the 4.x migration guide is the way there, and 4.0.1 made the upgrade one a dependency bot can offer.Full changelog: quartznet/quartznet@v3.20.1...v3.21.0
3.20.1
Quartz.NET 3.20.1 is a maintenance release: every change is a bug fix, the public API is untouched (the baselines did not move), and the schema is 3.20's. Most of it was found while 4.0 was being finished and rehearsed — a fix that turned out to be as old as 3.x was ported here rather than left on the newer line — and one item comes from a production application's 3.19.1 → 4.0 upgrade that also read on 3.x. Eight of the fixes change what a running scheduler does, each marked Behavior change worth noting below.
What changed
Landed on the branch since 3.20.0:
DailyTimeIntervalTriggerstored through the default Newtonsoft path reads back again —TimeOfDayhas no parameterless constructor, so with the trigger converters off (the default)EndTimeOfDaythrew "Unable to find a constructor" andStartTimeOfDaysilently read back as midnight. A converter scoped toTimeOfDay-typed members reads both forms; nothing about what is written changed, so every blob a released 3.20 wrote is one this reads. (9ee33fec17, fixes #3508)StartTimeUtckept its milliseconds while the fire times are counted in whole seconds, so a start of22:50:00.68could produce a first fire at22:50:00.000. Start and end are rounded down to the second when set, asCronTriggerImplalways did. (cc051a7788, #3386)RAMJobStoreand as a permanentCOMPLETErow in the ADO store. Both stores finish it now. (0af9431d3e, #3507)[DisallowConcurrentExecution]job is neither acquired nor swept, so the completion that unblocks it is the first thing that can settle its missed fire time;RAMJobStorenow does whatJobStoreSupport.RecoverUnblockedMisfiresalways did. (c9d8658a35, #3463)RAMJobStorewrotePausedoverError, so a failed trigger vanished from every listing once its group was paused andResetTriggerFromErrorStatehad nothing to reset. It now pauses only what the ADO store pauses: waiting, acquired and blocked triggers. (a56a16ca0c)RescheduleJobadvanced a never-fired repeating simple trigger's start time past a next fire time it kept, so it fired at the stale time and again at its start. (3e086091fc, #3554)overwrite-existing-dataon, and a repeating trigger that starts now fired twice milliseconds apart. (f25080cef6, #3554)Dictionary<string, string>job-data value written by the Newtonsoft package carried a$typethe System.Text.Json reader handed back as an entry, and one written by System.Text.Json came back from Json.NET as aJObject. Both readers read both shapes; neither writer changed. (83ba80ce79, part of #3582)QRTZ_SIMPROP_TRIGGERStoo — a database missing only that table passed validation and failed on the first calendar-interval, daily-time-interval or recurrence trigger insert. (b33c70487b, #3564)4b3c43a90e); untagged builds from the branch say 3.20 (0e2f6bcf31); the XML scheduling integration test opens its own fixture's data source (4c07210199, #3573).Ported from 4.0:
JobToBeExecutedescaped as itself rather than the exception the run shell catches, soTriggeredJobCompletewas never reached: the trigger stayed acquired and, for a[DisallowConcurrentExecution]job, every sibling trigger stayed blocked; the firing was also listed as executing for the life of the process. (port of #3502)IDX_QRTZ_T_NFT_ST_MISFIRE, whose second column is compared with<>and stops the seek dead. Measured on 4.x against 100,000 triggers: the count 111 ms → 0.7 ms, the sweep 66 ms → 0.7 ms. No schema change. (port of #3608)RescheduleJobandUpdateTriggerDetailson the ADO store resolved the job's class to decide whether the new trigger could run, and failed in an administration node without the assembly. Both read the job's two attribute flags fromQRTZ_JOB_DETAILSnow, so the decision is right without the class and a placeholderITypeLoadHelper— which decided that question by whether the placeholder carried the attribute — is no longer needed. (port of #3705)40001,40P01;40002excepted) is transient. Firebird reports a write conflict that way withIsTransientfalse, andMySql.Dataits 1213 deadlock. (port of #3454)SimpleTriggerinterval finer than a millisecond was stored as0, read back as zero, and left the trigger inACQUIREDfor good behind a divide-by-zero the store logged and swallowed. It is refused on write now, naming the trigger and the column;RAMJobStorekeeps accepting it. (port of #3673)List<string>or a nested object serialized happily and threw on the next read with the blob already in the database, and every later acquisition of the trigger failed on it. A value that would be stored as a JSON array, or as an object other than aDictionary<string, string>, is refused before the first byte is written, naming the entry and its type. Anything stored as a number or a string — every numeric type,DateTime,Guid,byte[],Uri— still round-trips exactly as before. (port of #3495)JsonSerializationExceptionat store time, where it used to be a blob the next read failed on. The refusal also covers three shapes that did not throw before but never came back as themselves either — a non-genericHashtable, an object whose properties are all strings, and aJobDataMapnested inside aJobDataMap— each of which the reader handed back as aDictionary<string, string>. Store one of those as a string of your own making.EndTimeUtcfalling between two fire times of the same day let the trigger go on firing until the daily window closed, andFinalFireTimeUtcreported that close even when it was a day past the end. (port of the daily half of #3458)NativeJobno longer deadlocks a child that writes more than a pipe buffer — both streams were redirected whether or notconsumeStreamsasked for them to be read, so with the defaults a chatty process blocked on its own write and the job's synchronous wait held a worker for ever. Nothing is redirected unless consumed. (port of the rc.1 fix)EnlistConnectioninside aTransactionScopetook aMicrosoft.Data.Sqliteconnection on trust, and SQLite cannot enlist, so every statement committed on the spot and a rolled-back scope left the schedule behind.EnlistTransaction(DbTransaction)still works there. (port of the beta.1 fix)now - MisfireThresholdwas a misfire toRAMJobStoreand to the ADO store's single-trigger path but not to its periodic sweep; the sweep says<=now and the acquisition predicate moved to>in step. (port of #3462)"3,14"read as314from the floating-point accessors whileGetIntthrew. (port of the beta.1 fix)GetDoubleandGetFloatthrow aFormatExceptionfor such a string where they used to answer a number a hundred times too large.[matches literally on SQL Server — T-SQL reads[as a character class inLIKE; it is escaped on that dialect only, because the standard forbids escaping a non-wildcard elsewhere. (port of the rc.1 fix)[matches the groups it names rather than the character class T-SQL read it as, so it can list, pause, resume or delete a different set than on 3.20.DirectoryScanJobstores its previous scan as something a job store can write — it kept aList<FileInfo>under[PersistJobDataAfterExecution], which System.Text.Json cannot write, so its first firing on such a store failed to persist. A legacy list already in a running scheduler is still read. (port of the rc.1 fix)DirectoryScanJobruns at all on 3.20 — it read its optional job-data keys withGetString, which throws for a key that is not there, so a job configured without a directory provider or listener name failed on every firing withKeyNotFoundException. Found while porting the previous item; the optional keys are asked for rather than read.SelectSchedulerStateRecordsbinds its parameters in statement order — only a provider withBindByNameoff could ever have noticed. (port of the alpha.3 fix)Public API
Unchanged. No signature was added, altered or removed, and the
PublicApiTestbaselines did not move.... (truncated)
Commits viewable in compare view.
Pinned Quartz.Serialization.SystemTextJson at 3.21.0.
Release notes
Sourced from Quartz.Serialization.SystemTextJson's releases.
3.21.0
Quartz.NET 3.21.0 carries the three fixes held back from 3.20.1 because each needed a small addition to the public surface or changed what a running scheduler does. All three were found while 4.0 was being finished; each is as old as 3.x. The public API grows by two interfaces on one class and nothing else; the schema is 3.20's. Three of the changes alter behaviour, each marked Behavior change worth noting below.
What changed
ResumeAllclears every paused trigger group, not only the ones with triggers — the persistent store resumed the groups it found inQRTZ_TRIGGERSand then deleted only its all-groups marker, so a group paused while it held no triggers kept itsQRTZ_PAUSED_TRIGGER_GRPSrow and went on pausing whatever was scheduled into it afterwards. Pausing a group before anything is scheduled into it is a documented use of the exact-name matcher, so this was a row the store wrote on purpose and could not take back. The trailing delete now takes every group, asRAMJobStorehas always done. (#3721, #3742, port of f76b04a468)ResumeAll.RedisSemaphoreopened aConnectionMultiplexeron the first lock and kept it, with its heartbeat, for the life of the process, because nothing on the store's shutdown path reached the lock handler andISemaphorehad no member that meant "we are done". On a branch that targetsnetstandard2.0andnet462an interface cannot gain a default member, soJobStoreSupport.Shutdownnow disposes a lock handler that implementsIAsyncDisposableorIDisposable, after the misfire handler, the cluster manager and the connection manager have stopped, logging and continuing if that throws;RedisSemaphoreimplements both and closes the multiplexer it opened. (#3721, #3742, port of #3639)ISemaphorethat implements either interface is now disposed at shutdown.Task.Delayrefuses anything longer than about 49.7 days on .NET and about 24.9 days on .NET Framework, with anArgumentOutOfRangeExceptionnaming a parameter calleddelay, and every duration Quartz waits out that way was accepted unchecked and reported later from wherever the wait happened.MisfireHandlerFrequency,MisfireThreshold(when it is also the handler's sleep),ClusterCheckinInterval,DbRetryInterval,TransientRetryInterval, the row-lock handlers'RetryPeriod,StartDelayed's argument andQuartzHostedServiceOptions.StartDelaynow name the setting, the ceiling and the value at configuration time. The ceiling is per target framework, held to whatTask.Delayactually accepts by a test. (#3721, #3742, port of #3577)Public API — additive only
Quartz.Extensions.Redis:RedisSemaphoreimplementsIAsyncDisposableandIDisposable.Upgrading
dotnet add package Quartz --version 3.21.0. Nothing to migrate. The 4.0 line is the current major; the 4.x migration guide is the way there, and 4.0.1 made the upgrade one a dependency bot can offer.Full changelog: quartznet/quartznet@v3.20.1...v3.21.0
3.20.1
Quartz.NET 3.20.1 is a maintenance release: every change is a bug fix, the public API is untouched (the baselines did not move), and the schema is 3.20's. Most of it was found while 4.0 was being finished and rehearsed — a fix that turned out to be as old as 3.x was ported here rather than left on the newer line — and one item comes from a production application's 3.19.1 → 4.0 upgrade that also read on 3.x. Eight of the fixes change what a running scheduler does, each marked Behavior change worth noting below.
What changed
Landed on the branch since 3.20.0:
DailyTimeIntervalTriggerstored through the default Newtonsoft path reads back again —TimeOfDayhas no parameterless constructor, so with the trigger converters off (the default)EndTimeOfDaythrew "Unable to find a constructor" andStartTimeOfDaysilently read back as midnight. A converter scoped toTimeOfDay-typed members reads both forms; nothing about what is written changed, so every blob a released 3.20 wrote is one this reads. (9ee33fec17, fixes #3508)StartTimeUtckept its milliseconds while the fire times are counted in whole seconds, so a start of22:50:00.68could produce a first fire at22:50:00.000. Start and end are rounded down to the second when set, asCronTriggerImplalways did. (cc051a7788, #3386)RAMJobStoreand as a permanentCOMPLETErow in the ADO store. Both stores finish it now. (0af9431d3e, #3507)[DisallowConcurrentExecution]job is neither acquired nor swept, so the completion that unblocks it is the first thing that can settle its missed fire time;RAMJobStorenow does whatJobStoreSupport.RecoverUnblockedMisfiresalways did. (c9d8658a35, #3463)RAMJobStorewrotePausedoverError, so a failed trigger vanished from every listing once its group was paused andResetTriggerFromErrorStatehad nothing to reset. It now pauses only what the ADO store pauses: waiting, acquired and blocked triggers. (a56a16ca0c)RescheduleJobadvanced a never-fired repeating simple trigger's start time past a next fire time it kept, so it fired at the stale time and again at its start. (3e086091fc, #3554)overwrite-existing-dataon, and a repeating trigger that starts now fired twice milliseconds apart. (f25080cef6, #3554)Dictionary<string, string>job-data value written by the Newtonsoft package carried a$typethe System.Text.Json reader handed back as an entry, and one written by System.Text.Json came back from Json.NET as aJObject. Both readers read both shapes; neither writer changed. (83ba80ce79, part of #3582)QRTZ_SIMPROP_TRIGGERStoo — a database missing only that table passed validation and failed on the first calendar-interval, daily-time-interval or recurrence trigger insert. (b33c70487b, #3564)4b3c43a90e); untagged builds from the branch say 3.20 (0e2f6bcf31); the XML scheduling integration test opens its own fixture's data source (4c07210199, #3573).Ported from 4.0:
JobToBeExecutedescaped as itself rather than the exception the run shell catches, soTriggeredJobCompletewas never reached: the trigger stayed acquired and, for a[DisallowConcurrentExecution]job, every sibling trigger stayed blocked; the firing was also listed as executing for the life of the process. (port of #3502)IDX_QRTZ_T_NFT_ST_MISFIRE, whose second column is compared with<>and stops the seek dead. Measured on 4.x against 100,000 triggers: the count 111 ms → 0.7 ms, the sweep 66 ms → 0.7 ms. No schema change. (port of #3608)RescheduleJobandUpdateTriggerDetailson the ADO store resolved the job's class to decide whether the new trigger could run, and failed in an administration node without the assembly. Both read the job's two attribute flags fromQRTZ_JOB_DETAILSnow, so the decision is right without the class and a placeholderITypeLoadHelper— which decided that question by whether the placeholder carried the attribute — is no longer needed. (port of #3705)40001,40P01;40002excepted) is transient. Firebird reports a write conflict that way withIsTransientfalse, andMySql.Dataits 1213 deadlock. (port of #3454)SimpleTriggerinterval finer than a millisecond was stored as0, read back as zero, and left the trigger inACQUIREDfor good behind a divide-by-zero the store logged and swallowed. It is refused on write now, naming the trigger and the column;RAMJobStorekeeps accepting it. (port of #3673)List<string>or a nested object serialized happily and threw on the next read with the blob already in the database, and every later acquisition of the trigger failed on it. A value that would be stored as a JSON array, or as an object other than aDictionary<string, string>, is refused before the first byte is written, naming the entry and its type. Anything stored as a number or a string — every numeric type,DateTime,Guid,byte[],Uri— still round-trips exactly as before. (port of #3495)JsonSerializationExceptionat store time, where it used to be a blob the next read failed on. The refusal also covers three shapes that did not throw before but never came back as themselves either — a non-genericHashtable, an object whose properties are all strings, and aJobDataMapnested inside aJobDataMap— each of which the reader handed back as aDictionary<string, string>. Store one of those as a string of your own making.EndTimeUtcfalling between two fire times of the same day let the trigger go on firing until the daily window closed, andFinalFireTimeUtcreported that close even when it was a day past the end. (port of the daily half of #3458)NativeJobno longer deadlocks a child that writes more than a pipe buffer — both streams were redirected whether or notconsumeStreamsasked for them to be read, so with the defaults a chatty process blocked on its own write and the job's synchronous wait held a worker for ever. Nothing is redirected unless consumed. (port of the rc.1 fix)EnlistConnectioninside aTransactionScopetook aMicrosoft.Data.Sqliteconnection on trust, and SQLite cannot enlist, so every statement committed on the spot and a rolled-back scope left the schedule behind.EnlistTransaction(DbTransaction)still works there. (port of the beta.1 fix)now - MisfireThresholdwas a misfire toRAMJobStoreand to the ADO store's single-trigger path but not to its periodic sweep; the sweep says<=now and the acquisition predicate moved to>in step. (port of #3462)"3,14"read as314from the floating-point accessors whileGetIntthrew. (port of the beta.1 fix)GetDoubleandGetFloatthrow aFormatExceptionfor such a string where they used to answer a number a hundred times too large.[matches literally on SQL Server — T-SQL reads[as a character class inLIKE; it is escaped on that dialect only, because the standard forbids escaping a non-wildcard elsewhere. (port of the rc.1 fix)[matches the groups it names rather than the character class T-SQL read it as, so it can list, pause, resume or delete a different set than on 3.20.DirectoryScanJobstores its previous scan as something a job store can write — it kept aList<FileInfo>under[PersistJobDataAfterExecution], which System.Text.Json cannot write, so its first firing on such a store failed to persist. A legacy list already in a running scheduler is still read. (port of the rc.1 fix)DirectoryScanJobruns at all on 3.20 — it read its optional job-data keys withGetString, which throws for a key that is not there, so a job configured without a directory provider or listener name failed on every firing withKeyNotFoundException. Found while porting the previous item; the optional keys are asked for rather than read.SelectSchedulerStateRecordsbinds its parameters in statement order — only a provider withBindByNameoff could ever have noticed. (port of the alpha.3 fix)Public API
Unchanged. No signature was added, altered or removed, and the
PublicApiTestbaselines did not move.... (truncated)
Commits viewable in compare view.
Pinned Radzen.Blazor at 11.3.2.
Release notes
Sourced from Radzen.Blazor's releases.
11.3.2
11.3.2 - 2026-09-04
Improvements
Fixes
11.3.1
11.3.1 - 2026-09-03
Improvements
Fixes
11.3.0
11.3.0 - 2026-09-02
Improvements
Fixes
Commits viewable in compare view.
Pinned WolverineFx.Marten at 6.36.0.
Release notes
Sourced from WolverineFx.Marten's releases.
6.36.0
Heads up when upgrading
CircuitBreaker()on a buffered local queue now stops the host from starting with anInvalidListenerConfigurationException(#4410, #4412). A buffered local queue can't pause, so the circuit breaker used to be accepted and then silently ignored. AddUseDurableInbox()to the queue, oropts.Policies.UseDurableLocalQueues(), or remove the circuit breaker. Durable local queues and external listeners are unaffected. If you use WolverineFx.AI withDurableQueue = falseplus a circuit breaker on the callout queue, this applies to you too.SlicePattern.Command(#4413).New
[SlicePattern]declares the Event Model slice pattern of a message handler whose message has no producer in the model, such as a message from another service or a hosted service (#4395, #4413). It only fills the gap: an HTTP route, gRPC RPC, schedule or inbound external system still decides the pattern.ActivityLink(#4398, #4405).Fixes
System.Security.Cryptography.Xmlis now 10.0.12, clearing a high-severity advisory (#4401).Docs
System.Threading.Channels, not TPL Dataflow (#4411).EnableNodeAgentSupport()from the exclusive node processing page (#4414).6.35.0
Store operation side effects, everywhere
MartenOpscovered store / insert / update / delete plusStartStream; anything else meant taking anIDocumentSessionand giving up on the handler being a pure function. All three stores now coverwhat their own session API supports.
HardDelete,HardDeleteWhere,UndoDeleteWhereUpdateExpectedVersionUpdateRevisionTryUpdateRevisionPatch,PatchWhereQueueSqlCommandInsertObjects,DeleteObjectsAppend,ArchiveStreamUnArchiveStream,TombstoneStreamThe gaps are deliberate: each set was checked against that store's own session API rather than copied
across, and an op whose
Executecould only throw is worse than the absence of one. Polecat's lastrow is the reverse case — two operations Marten has no counterpart for.
Every op also implements
ITenantedMartenOp/ITenantedPolecatOp/ITenantedFisherOp, so oneextension scopes any of them while preserving the concrete return type:
Thanks to @erdtsieck for the Marten half, which is where this started.
Event Modeling: a declared model and the code now meet
Three findings from one comparison of a curated Event Model against the application built from it
(#4385, #4386, #4387):
behaviour (
ConfirmAppointment) while a derived source names it for the message type or the route.An eleven-slice application assembled as twenty-two with no disagreements — not because the sources
agreed, but because they never met.
[Emits(typeof(...))]lets a handler nam....Description has been truncated