Releases: JasperFx/marten
Release list
Marten 9.15.0
Closed issues
- #4942 — sharded tenancy: auto-assign never repaired half-provisioned tenants (PR #4945).
findOrAssignTenantDatabaseAsyncreturned early on an existing assignment row, skippingcreatePartitionsForTenant+ per-tenant event-sequence provisioning — so a tenant whose provisioning was interrupted (assignment committed, partitions missing) failed every write with23514forever. Both early-return paths (including a second race-window hole under the advisory lock) now run the same idempotent repair the explicitAddTenantToShardAsync(tenantId, databaseId)overload always ran, guarded to once per process per tenant via the resolution cache. - #4941 — two-day silent projection outage (closed with full mapping). Root cause was #4942; the invisibility was JasperFx/jasperfx#506/#507, fixed in JasperFx 2.27.0 which this release consumes.
Also in this release
- Bundles the fixed
JasperFx.Events.SourceGeneratoranalyzer (JasperFx/jasperfx#505) — CS1061 compile break for no-parameterless-ctor aggregates with instanceApplyreturning the aggregate. - Follow-up enhancement filed as #4944 (database-driven partition sweep via
pg_inherits) for the #4943 provisioning-tool scenario.
Verified against Wolverine (full solution + CoreTests/MartenTests/distribution/Http suites, zero failures) and CritterWatch before publishing. Thanks to @erdtsieck for the dump-verified root-cause analysis.
Marten 9.14.1
Marten 9.14.1 is a patch release focused on a substantial round of LINQ query-translation improvements, plus event-store partitioning, high-water, and AoT fixes, and refreshed Weasel/JasperFx dependencies.
LINQ query translation
This release significantly expands what the LINQ provider can push down to PostgreSQL instead of falling back to slower strategies or throwing:
- Collection
Any(predicate)filters now translate to JSONPath and OR-of-containment strategies, and the old explode/ctidfallback has been replaced by a correlatedEXISTSstrategy.All()shapes and duplicated array fields moved onto the sameEXISTSstrategy. The net effect is correct, index-friendlier SQL for nested-collection predicates. - Indexing into complex child collections inside
Where()clauses is now supported (e.g.x.Children[0].Name == "..."). - Aggregates over collections —
Sum/Min/Max/Average— can now be used insideWhere()clauses. Regex.IsMatch()is translated inWhere()clauses.IComparable.CompareTo()now works for non-string comparables such asGuid(#4920), alongside broaderCompareTo()coverage,stringIsOneOfvia the?|operator, andCollectionIsEmptyviaICollectionAware.GinIndexJsonDataMember()was added for member-scoped expression GIN indexes.
#4916 — subclass queries now use duplicated fields and the base id
Querying a document subclass and filtering on a Duplicate()'d field or the base-class id previously emitted a JSONB filter (CAST(d.data ->> 'FarmId' as uuid)) instead of the real column, missing the duplicated column and the primary-key index:
o.Schema.For<Animal>().AddSubClass<Cow>().Duplicate(x => x.FarmId);
Query<Cow>().Where(x => x.FarmId == id) // now: d.farm_id = :p0 (was: CAST(d.data ->> 'FarmId' ...))
Query<Cow>().Where(x => x.Id == id) // now: d.id = :p0 (was: CAST(d.data ->> 'Id' ...))A subclass shares its parent's table, so the parent's column-backed members (duplicated fields, the id, the soft-delete flag) are now inherited by the subclass's query member resolution. Querying the parent type was already correct and is unchanged.
Event store, partitioning & daemon
- #4924 — hyphenated / GUID tenant ids under
UseTenantPartitionedEvents. Registering a tenant whose partition suffix contains a-(so every GUID tenant id) madeApplyAllConfiguredChangesToDatabaseAsync()throw42601because the per-tenantCREATE SEQUENCE/DROP SEQUENCEDDL emitted the identifier unquoted. The schema-apply statements are now quoted (matching the quick-append function and the imperative provisioning path), so hyphenated tenants migrate cleanly. Quote — not sanitize — so the append function can still resolve the sequence by its raw suffix. - #4915 — projection coordinator shutdown. The projection coordinator now drains on disposal, and via the Weasel 9.16.3 bump the advisory-lock
ObjectDisposedExceptionpath latches-and-rethrows so a HotCold cold node's leadership loop terminates instead of re-polling a disposed data source during shutdown. - #4913 — high-water scan under partitioning (JasperFx 2.26.0). Under
UseTenantPartitionedEventsthe store-global high-water agent was continuously runningselect max(seq_id) from mt_events, an unfiltered scan that fans out across every tenant partition on every poll. That store-global mark is not used to advance tenant projections (they advance per-tenant), so the recurring scan is now skipped under partitioning; tenant high water is driven by the per-tenant coordinator and poll timer. - #502 (#4922) —
GetProjectionStatusesAsyncnow resolves the correct named database.
AoT / trimming
- #4917 — corrected AoT annotations in the event graph.
- The
AddEventType/QueryRawEventDataOnlygeneric-constraint tightening was reversed, and event-mapping construction now routes through the cachedGenericFactoryCachewhile preserving the trimming root (#4930).
Dependencies
- Weasel 9.16.3 (#4932) — advisory-lock disposed-pool fix (marten#4915).
- JasperFx 2.26.0 — the #4913 high-water fix, plus 2.25.0's
ShardState.DatabaseIdentifier(#501).
Closed issues
Marten 9.14.0
Marten 9.14.0 is the recommended upgrade for all 9.x users. It combines the LINQ SQL-injection security fix (first shipped in 9.13.0) with the fix for the projection-coordinator shutdown race in #4874 and the accompanying dependency updates.
Beyond the LINQ updates, this made the new Per-Tenant Event Partitioning much more robust as we're testing that in conjunction with a JasperFx client for ludicrous scalability.
🔒 Security — SQL injection in the LINQ provider (GHSA-rfx3-98h7-v3xp)
Several LINQ / tenant-management code paths interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted literal without escaping or parameterization. A value containing a single quote could break out of the literal and inject SQL. The primary vector — a Dictionary<,> indexer key in a Where filter (a common "filter by attribute name" / EAV pattern) — was reported privately with an executed proof-of-concept and enabled filter / multi-tenant authorization bypass and blind data exfiltration.
Fixed sinks (#4911):
DictionaryItemMember— dictionary indexer key, e.g.Where(x => x.Attributes[key] == v)DictionaryContainsKeyFilter—Dictionary.ContainsKey(key)(Newtonsoft serializer + the Enum branch, which bypass System.Text.Json's quote escaping)SelectParser— a constant string projected throughSelect(x => new { L = runtimeString })DeleteAllForTenant— tenant id reaching per-tenant projection teardown (now parameterized)DatabaseScopedTenantPartitions— tenant id inlined into partition DDLEventLoader— per-tenant partition-pruning literal (defense-in-depth)
Each sink now escapes embedded single quotes or binds the value as a parameter; regression tests lock down every vector, and a follow-up LINQ-wide audit cleared the rest of the query hot path (full-text search, string-method translations, comparisons, IsOneOf/Contains/subset operators, and patching paths). Affected versions: 7.0.0 – 9.12.0. Also patched in 8.37.4 (8.x line) and 9.13.0.
Reported responsibly by @svenclaesson — thank you. See advisory GHSA-rfx3-98h7-v3xp (CVE pending assignment).
🛠️ Reliability — projection-coordinator shutdown drain race (#4874)
On host shutdown, the native HotCold projection coordinator could abort with ObjectDisposedException: 'Npgsql.PoolingDataSource' — the coordinator's leadership poll issued an OpenAsync against an already-disposed data source while tenancy was tearing down. This is the "case B" ordering storm reported against #4874 (distinct from the async-tenancy foundation laid in #4907, which did not resolve it).
The fix ships through the dependency updates below, with a Marten-side regression test (Bug_4874_coordinator_drain_ordering, #4912):
- JasperFx 2.24.1 (#499/#500) —
ProjectionCoordinatorBaseterminates the leadership loop on a disposed data source / wrapped cancellation instead of re-polling. - Weasel 9.16.2 (weasel#349/#350) —
AdvisoryLockguards against a disposedNpgsqlDataSourceduring shutdown (short-circuits while disposing and treats a disposed-poolObjectDisposedExceptionas a non-acquire rather than propagating).
⬆️ Dependency updates
- JasperFx 2.24.0 → 2.24.1
- Weasel 9.16.1 → 9.16.2
- Weasel.EntityFrameworkCore 9.2.1 → 9.16.2 (released from its prior version hold now that the Weasel line is published)
Full changelog since 9.13.0
Marten 9.13.0
Security release. Fixes SQL injection in the LINQ provider via unescaped string literals (#4911).
Several LINQ / tenant-management code paths interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted literal without escaping or parameterization; a value containing a single quote could break out and inject SQL. The primary vector — a Dictionary<,> indexer key in a Where filter — was reported privately with an executed proof-of-concept (filter / multi-tenant authorization bypass, blind exfiltration).
Fixed sinks:
DictionaryItemMember— dictionary indexer keyDictionaryContainsKeyFilter—ContainsKeykey (Newtonsoft serializer + Enum branch)SelectParser— constant string projected viaSelect(...)DeleteAllForTenant— tenant id in per-tenant projection teardown (now parameterized)DatabaseScopedTenantPartitions— tenant id in partition DDLEventLoader— per-tenant partition-pruning literal (defense-in-depth)
All 9.x users should upgrade. The 8.x line is fixed in 8.37.4. See advisory GHSA-rfx3-98h7-v3xp.
Marten 8.37.4
Security release. Fixes SQL injection in the LINQ provider via unescaped string literals.
Several LINQ code paths interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted literal without escaping or parameterization; a value containing a single quote could break out and inject SQL. The primary vector — a Dictionary<,> indexer key in a Where filter — was reported privately with an executed proof-of-concept (filter / multi-tenant authorization bypass, blind exfiltration).
Fixed sinks (this 8.x line):
DictionaryItemMember— dictionary indexer keyDictionaryContainsKeyFilter—ContainsKeykey (Newtonsoft serializer + Enum branch)SelectParser— constant string projected viaSelect(...)
All users on 8.x should upgrade. A GitHub Security Advisory (with CVE) is being coordinated.
Back-port of #4911 (9.x).
V9.12.0
A couple significant bug fixes, and yet more support for CritterWatch
What's Changed
- feat: populate event/document metadata capabilities + tenant-scoped document diagnostics (9.12.0-alpha.1) by @jeremydmiller in #4790
- Implement metadata-filtered document + event queries (#4791) by @jeremydmiller in #4792
- Fix #4788 — repopulate mt_natural_key on projection rebuild (supersedes #4789) by @jeremydmiller in #4793
- Fix #4787 — consume JasperFx 2.18.1 (DI-projection partial-class dispatch) by @jeremydmiller in #4794
Full Changelog: V9.11.0...V9.12.0
V9.11.0
What's Changed
- Implement IDocumentStoreDiagnostics + enrich mapping descriptor (9.11.0-alpha.1) by @jeremydmiller in #4776
- Fix #4761 follow-up: WaitForNonStaleData global-shard fallback under tenant partitioning (9.11.0-alpha.2) by @jeremydmiller in #4777
- Range-partition a document table by a non-tenant date column (#4779) by @jeremydmiller in #4780
- Test coverage for document diagnostics (#4775) by @jeremydmiller in #4781
- Emit runtime event-append observations via IEventStoreInstrumentation (#4782) by @jeremydmiller in #4783
- Fix false ConcurrencyException from non-RETURNING event ops in batched SaveChanges (#4778) by @jeremydmiller in #4784
- Implement IEventDatabase.DeleteProjectionProgressByShardNameAsync (#4785) by @jeremydmiller in #4786
Full Changelog: V9.10.0...V9.11.0
V9.10.0
The new option might help the async daemon perform better in the face of concurrency exceptions on event appending with the QuickAppend option. It's opt in to avoid folks needing to do schema migrations
What's Changed
- Bump dompurify from 3.4.10 to 3.4.11 by @dependabot[bot] in #4770
- Bump http-proxy-middleware from 3.0.5 to 3.0.7 by @dependabot[bot] in #4769
- #4772: verify SubscriptionDescriptor carries ImplementationType/AggregateType by @jeremydmiller in #4773
- fix: close mt_events_sequence gap on concurrent Quick OCC failures (#4749) by @KMDjkb in #4771
New Contributors
Full Changelog: V9.9.1...V9.10.0
Marten 8.37.3
Maintenance release on the 8.0 line.
Fixes
-
#4718 —
projections rebuildmust skip subscriptions. When an event subscription was registered (e.g. Wolverine'sPublishEventsToWolverine(...)withSubscribeFromPresent()),dotnet run -- projections rebuildthrewNo registered projection matches the name '...'. A subscription isAsync, so its name was fed into the rebuild path →RebuildProjectionAsync→TryFindProjection(which only searches projections). The rebuild path now skips event subscriptions andLive-lifecycle projections. Subscriptions still run continuously and still appear inprojections list; only rebuild skips them, and a subscription name passed explicitly to rebuild is a clean no-op.Backported to the JasperFx 1.x line in JasperFx.Events 1.36.2 (JasperFx/jasperfx#460, tracked by JasperFx/jasperfx#459).
Dependencies
- JasperFx.Events
1.35.0→1.36.2 - JasperFx
1.29.1→1.31.0
V9.9.1
This will be a valuable upgrade for anyone who experiences a high degree of optimistic concurrency failures while using QuickAppend options, which is the default behavior in V9. This will help stop gaps in the event sequence, which in turn will make the Async Daemon healthier.
Also though, see Wolverine for help in preventing concurrent access in the first place
What's Changed
- Fix #4761 + #4763: per-tenant non-stale wait + sharded reassignment tenant_count by @jeremydmiller in #4764
- Fix #4765: close mt_events_sequence gap on Quick + ExpectedVersion OCC failure by @jeremydmiller in #4766
- #4751: regression test for async composite catch-up under sharded + tenant-partitioned by @jeremydmiller in #4767
- Register JasperFx.Events IProjectionCoordinator base interface (#430) + JasperFx 2.13.1 / Weasel 9.2.1 by @jeremydmiller in #4768
Full Changelog: V9.9.0...V9.9.1