avoid very small amount of alloc by using ValueTask.CompletedTask#486
Merged
Conversation
Member
|
@SimonCropp I'd read somewhere that this wasn't actually helpful. Something to do w/ heap vs stack mechanics |
Contributor
Author
|
@jeremydmiller news to me. can u find a reference? |
jeremydmiller
added a commit
that referenced
this pull request
Jul 7, 2026
…urn/failover e2e, #4862 regression pin (#486) (#3334) * Consume Marten 9.13.0-alpha.3 + JasperFx 2.21.0 (epic #486 WS0/WS1) Marten 9.13.0-alpha.3 carries the per-tenant distribution work this PR's e2e tests exercise: marten#4864 (broadened DistributesAgentsPerTenant gate + single-DB descriptor TenantIds), marten#4865 (ExternallyManaged honored), marten#4869 (per-tenant high-water advancement — unblocks the failover floor-continuity test), and marten#4870 (native per-tenant distribution). JasperFx/JasperFx.Events pins move 2.20.0 -> 2.21.0 to match what Marten alpha.3 already pulls transitively — keeps the explicit pins from drifting below the resolved graph. No envelope-operation contract drift from marten#4872 (Weasel 9.12 metadata binders): Wolverine.Marten's StoreIncomingEnvelope/StoreOutgoingEnvelope compile unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * E2E: runtime tenant churn under Wolverine-managed distribution (#486 WS1) Sharded + UseTenantPartitionedEvents, single node: with tenant-a's per-tenant agent already projecting, add tenant-b to the same shard database at RUNTIME via Advanced.AddTenantToShardAsync. Within the assignment-evaluation window (CheckAssignmentPeriod = 1s) the leader re-enumerates the store usage, fans out the ":all/tenant-b" agent, tenant-b's fresh seq-1.. events project, its HighWaterMark-independent PartitionedCounter:All:tenant-b progression row lands in the shard database, and no store-global (tenant-less) agent ever runs alongside the per-tenant agents (the #3328 stale-agent-retirement edge). Tenant REMOVAL is deliberately not covered end-to-end: Marten 9.13.0-alpha.2 exposes RemoveTenantAsync/DisableTenantAsync (ShardedTenancy.cs:378/:470), but a running store's usage never shrinks - MartenDatabase.TenantIds is add-only (Fill at ShardedTenancy.cs:211/:364) and DescribeDatabasesAsync copies that in-memory list, so Wolverine keeps enumerating the removed tenant's agent until a process restart. The Wolverine half of the removal transition stays pinned by the running_per_tenant_agent_is_stopped_when_its_tenant_is_removed unit test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * E2E (pinned/skipped): failover preserves per-tenant progression floors (#486 WS1) Two nodes, sharded + UseTenantPartitionedEvents, two tenants co-located on one shard database: append N events per tenant, record each tenant's progression floor, kill the node owning the affine agent group, assert the survivor picks both agents up and resumes tenant-b exactly from its floor (doc == N+M, no skips, no rewind) after M more post-failover events. SKIPPED, pinning a Marten 9.13.0-alpha.2 product bug found by this test: the failover mechanics work (survivor restarts both agents, floors never rewind, tenant-a intact), but per-tenant high-water detection FREEZES at the first persisted HighWaterMark:<tenant> row - HighWaterDetector.loadPerTenantStatistics (src/Marten/Events/Daemon/HighWater/HighWaterDetector.cs:260): var currentMark = lastSeqId > 0 ? lastSeqId : lastValue; Once the row exists, CurrentMark is pinned to it and max(seq_id) is never consulted again, so ANY second batch of events per tenant never projects (not failover-specific; sibling tests all append one batch per tenant and never see it). Empirically confirmed: tenant-b at max seq_id 11 committed, store-global HighWaterMark advanced to 11 (global detection + per-tenant poll trigger both firing), HighWaterMark:tenant-b frozen at 6. Unskip on the Marten-side fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Unskip the failover floor-continuity test — fixed by marten#4869 in 9.13.0-alpha.3 The skip pinned marten#4867: per-tenant high-water detection froze at the first persisted HighWaterMark:<tenant> row, so the M post-failover tenant-b events never projected. Marten 9.13.0-alpha.3 advances per-tenant CurrentMark past the persisted row (marten#4869), which makes the final leg pass. The class comment keeps a condensed history of the pinned bug. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Regression test for marten#4862: single-DB tenant-partitioned per-tenant distribution (#486 WS1) Promotes the WS1 single-database fact-finding probe (found the bug 2026-07-06) into the marten#4862 regression test. Against Marten 9.13.0-alpha.2 a single-database store reported DistributesAgentsPerTenant = false, so managed distribution ran ONE store-global agent whose progression floor (driven to the leading tenant's max per-tenant seq) permanently skipped a lagging tenant's later events at per-tenant seq 1..N — the wolverine#3280 failure mode on one database. Marten 9.13.0-alpha.3 (marten#4864) broadens the gate to any tenant-partitioned store, so the startup expectation flips to per-tenant fan-out (2 tenants -> 2 agents) and the lagging-tenant projection assertions now pass unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Flip single-DB distribution granularity tests to per-tenant fan-out (marten#4862/#4864) With Marten 9.13.0-alpha.3, DistributesAgentsPerTenant is true for ANY tenant-partitioned store, so one async projection over a single tenant-partitioned database now fans out one subscription agent per managed tenant instead of a single store-global "/all" agent whose lone progression floor could silently skip a lagging tenant. - tenant_partitioned_distribution_granularity: 1 agent -> 3 (one per registered tenant, default tenant included), agent URIs carry the tenant in the shard path - tenant_partitioned_distribution_multinode: 2 store-global agents -> 6 per-tenant agents (2 projections x 3 tenants), spread 3+3 across the cluster and all reassigned to the survivor on node loss - AssignmentWaiter.WritePersistedActualsAsync no longer throws KeyNotFoundException when the database holds a node record the waiter isn't tracking (ghost rows from a hard-stopped prior run); it reports the untracked node instead so the TimeoutException diagnostic survives Part of #486 WS1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Ancillary stores: dispatch message-store shape on database cardinality, not tenancy type name Marten 9.13.0-alpha.3 (marten#4864) gives a single-database store with UseTenantPartitionedEvents a TenantPartitionedSingleDatabaseTenancy — a DefaultTenancy subclass, chosen precisely so 'is DefaultTenancy' dispatch keeps working. The ancillary IntegrateWithWolverine seam compared Tenancy.GetType().Name == "DefaultTenancy" instead, so such a store was misrouted to the multi-tenanted message-database path and host startup failed with "no configured connectivity for the required master PostgreSQL message database" after 20 broker retries (the CIMarten failure on this PR). Both the Marten and Polecat ancillary seams now dispatch on Tenancy.Cardinality == DatabaseCardinality.Single, mirroring the main-store integration (WolverineOptionsMartenExtensions), which is why only ancillary stores were affected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
jeremydmiller
added a commit
that referenced
this pull request
Jul 7, 2026
#492/#493) (#3335) JasperFx 2.21.1 drives the vectorized per-tenant high-water poll from the daemon's own SlowPollingTime timer instead of solely from store-global mark changes, so a lagging tenant appending below the global max converges without unrelated tenant activity. Epic #486 (WS1 residue). Full wolverine.slnx Release build + MartenTests.Distribution folder green locally (31 tests, net9.0). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
jeremydmiller
added a commit
that referenced
this pull request
Jul 7, 2026
#494-#496) (#3336) JasperFx 2.22.0 bounds the async daemon's database connection footprint per database: MaxConcurrentEventLoadsPerDatabase (event-load throttle) and MaxConcurrentBatchWritesPerDatabase (projection batch-write governor), both default 4 and on by default, plus a bounded CrossTenantRebuild default. Measured at 200 per-tenant agents on one database: peak connections drop from 47-99 to a deterministic 12-14 with unchanged throughput and catch-up (epic #486 WS2+WS3; numbers on #494). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
jeremydmiller
added a commit
that referenced
this pull request
Jul 7, 2026
jeremydmiller
added a commit
that referenced
this pull request
Jul 14, 2026
…3422) Connections are a resource of the database server, not of a logical database. That distinction is invisible when an application talks to one database, and load-bearing in the sharded-tenancy deployment #3397 comes from: hundreds of tenant databases spread over a handful of Postgres clusters, all drawing on the same finite pool, with the failures showing up as diffuse things like a schema apply job that cannot get a connection. This is phase 1 only: measure and surface. Wolverine reports connection pressure; it does not yet react to it. The adaptive back-off half needs hooks that live in JasperFx.Events' DaemonSettings (the polling knobs and the #486 governors are not Wolverine's), and it needs #3376 to resolve first since that changes the baseline any tuning would work against. - DatabaseServerId keys the budget by (engine, host, port). DatabaseDescriptor's ServerName is host-only, so two clusters co-hosted on one box would otherwise collide onto a single budget. SQL Server leaves Port null, since its Data Source already carries the port or named instance. - IConnectionBudgetProbe is an optional store capability, implemented for PostgreSQL and SQL Server. Providers without a cheap server-wide connection count simply do not implement it and drop out of the sweep. - The probe rides the existing metrics sweeper and is deduped by server: one query per server per pass, however many tenant databases the node owns. Probing per database would multiply the very pressure the number exists to reveal. - The max side of the budget is explicit configuration, not the server's max_connections. Behind a pooler, the server's limit describes what the pooler may open, not what the application is entitled to take; charting utilization against it would be reassuring and wrong. A probed limit is the labelled fallback when nothing is declared, and "unknown" is reported honestly when neither exists (SQL Server without VIEW SERVER STATE degrades to one warning, not a failed sweep). - Surfaced as OTel gauges tagged by server, and as IWolverineObserver.ConnectionBudget for CritterWatch. The observer member is a default no-op, so existing observers are unaffected. Active by default only for the statically-known-multiple-databases shape (Marten's MultiTenantedWithShardedDatabases), where a per-server number tells you something a per-database count cannot. Declaring a budget is itself an opt-in. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
No description provided.