Remove sync-over-async where possible, consolidate blocking into helpers, add analyzers#1714
Merged
kevin-montrose merged 20 commits intomainfrom Apr 28, 2026
Merged
Conversation
…ult()) have been removed
…tly, but also more unique for searching
… 'could be async' code
Contributor
There was a problem hiding this comment.
Pull request overview
This PR modernizes Garnet’s async usage by removing sync-over-async patterns where feasible, centralizing unavoidable blocking into a single helper, and adding analyzers/configuration to prevent regressions (notably around Async suffix rules and blocking waits).
Changes:
- Introduces
Garnet.common.AsyncUtilsand replaces scattered.GetAwaiter().GetResult()/.Result/.Wait()withAsyncUtils.BlockingWait(...)in explicitly-justified synchronous contexts (e.g., network thread, disposal, startup). - Renames many async-returning APIs to follow .NET async naming conventions (adds
Asyncsuffix) and updates call sites/tests accordingly; adds missing.ConfigureAwait(false)in multiple places. - Adds
Microsoft.VisualStudio.Threading.Analyzersacross several projects and configures VSTHRD analyzer severities in.editorconfig.
Reviewed changes
Copilot reviewed 94 out of 94 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Garnet.test/TaskManagerTests.cs | Updates tests to use WaitAsync and async test methods. |
| test/Garnet.test/RespVectorSetTests.cs | Converts recovery tests to async; updates commit waits to async. |
| test/Garnet.test/RespSortedSetTests.cs | Switches AOF commit usage to async in recovery test. |
| test/Garnet.test/RespHashTests.cs | Switches AOF commit usage to async in recovery test. |
| test/Garnet.test/RespAofTests.cs | Converts many AOF tests to async and awaits commits. |
| test/Garnet.test/RespAofAzureTests.cs | Converts Azure AOF tests to async and awaits commits. |
| test/Garnet.test/MultiDatabaseTests.cs | Converts multi-db AOF recovery tests to async and awaits commits. |
| test/Garnet.test/GarnetJSON/JsonCommandsTest.cs | Converts JSON AOF recovery test to async and awaits commit. |
| test/Garnet.test.cluster/ReplicationTests/ClusterReplicationBaseTests.cs | Makes manual checkpointing test async; awaits commit calls. |
| modules/GarnetJSON/GarnetJSON.csproj | Adds VS threading analyzers package reference. |
| metrics/HdrHistogram/Utilities/WriterReaderPhaser.cs | Replaces Task-based yielding/delay with Thread.Yield/Sleep. |
| metrics/HdrHistogram/HdrHistogram.csproj | Adds VS threading analyzers package reference. |
| main/GarnetServer/GarnetServer.csproj | Adds VS threading analyzers package reference. |
| libs/storage/Tsavorite/cs/src/core/Device/RandomAccessLocalStorageDevice.cs | Removes sync-over-async fast path; always awaits pool GetAsync(). |
| libs/server/TaskManager/TaskType.cs | Updates doc links to renamed StoreWrapper.*Async task implementations. |
| libs/server/TaskManager/TaskManager.cs | Replaces blocking waits with AsyncUtils.BlockingWait; renames Cancel to CancelAsync; removes sync Wait. |
| libs/server/StoreWrapper.cs | Renames checkpoint/task methods to *Async; removes sync AOF commit/wait helpers; adds ConfigureAwait(false) broadly. |
| libs/server/Servers/StoreApi.cs | Removes sync AOF commit/wait; standardizes on CommitAOFAsync/WaitForCommitAsync. |
| libs/server/ServerConfig.cs | Moves blocking index grow to AsyncUtils.BlockingWait on network thread; introduces HandleIndexSizeChangeAsync. |
| libs/server/Resp/Vector/VectorManager.Replication.cs | Refactors replication replay tasks to pure async; removes sync waits in cancellation; adds blocking helper for disposal-only paths. |
| libs/server/Resp/Vector/VectorManager.cs | Replaces .Wait() calls in Dispose with AsyncUtils.BlockingWait. |
| libs/server/Resp/RespServerSession.cs | Uses AsyncUtils.BlockingWait for AOF commit waits on network thread. |
| libs/server/Resp/PubSubCommands.cs | Switches cluster publish forwarding to async API + blocking helper on network thread. |
| libs/server/Resp/Objects/SortedSetCommands.cs | Replaces .Result with AsyncUtils.BlockingWait for blocking pops on network thread. |
| libs/server/Resp/Objects/ListCommands.cs | Replaces .Result with AsyncUtils.BlockingWait for blocking list operations on network thread. |
| libs/server/Resp/BasicCommands.cs | Suppresses VSTHRD200 for NetworkGETAsync naming; removes ineffective ConfigureAwait(false) on Task.Run. |
| libs/server/Resp/AsyncProcessor.cs | Renames AsyncGetProcessor to AsyncGetProcessorAsync. |
| libs/server/Resp/AdminCommands.cs | Uses TakeCheckpointAsync and blocks via helper on network thread; switches COMMITAOF to async path. |
| libs/server/PubSub/SubscribeBroker.cs | Renames broker loop to StartAsync and updates launcher. |
| libs/server/Objects/ItemBroker/CollectionItemBroker.cs | Renames main loop Start -> StartAsync; adds ConfigureAwait(false) where needed. |
| libs/server/Metrics/GarnetServerMonitor.cs | Switches monitor loop to Task-returning async method with forced async start. |
| libs/server/Garnet.server.csproj | Adds VS threading analyzers package reference. |
| libs/server/Databases/SingleDatabaseManager.cs | Makes checkpointing async end-to-end; removes sync continuations; updates index growth to async ValueTask. |
| libs/server/Databases/MultiDatabaseManager.cs | Makes checkpointing async; converts index growth to async fan-out with Task.WhenAll. |
| libs/server/Databases/IDatabaseManager.cs | Renames checkpoint and index-growth APIs to async signatures. |
| libs/server/Databases/DatabaseManagerBase.cs | Converts index auto-grow to async flow; replaces async commits with sync Commit() in compaction path. |
| libs/server/Cluster/IClusterProvider.cs | Switches publish API to ClusterPublishAsync (ValueTask). |
| libs/server/Auth/Aad/IssuerSigningTokenProvider.cs | Centralizes blocking wait on OIDC config fetch via AsyncUtils.BlockingWait. |
| libs/server/AOF/AofProcessor.cs | Uses blocking helper for checkpointing in replica replay path. |
| libs/host/Garnet.host.csproj | Adds VS threading analyzers package reference. |
| libs/host/Configuration/Options.cs | Removes sync-over-async for endpoint parsing by calling sync Format.TryCreateEndpoint. |
| libs/common/Networking/TcpNetworkHandlerBase.cs | Simplifies override to return base task (no async state machine). |
| libs/common/Networking/TaskToApm.cs | Uses AsyncUtils.BlockingWait for End methods; fixes ArgumentNullException parameter name. |
| libs/common/Networking/NetworkHandlerStream.cs | Renames internal async read helper to ReadAsyncInternalAsync. |
| libs/common/Networking/NetworkHandler.cs | Blocks client TLS auth in Start; uses blocking helper for completed SslStream.ReadAsync path. |
| libs/common/LightClient.cs | Introduces sync socket connect path; uses sync network handler start. |
| libs/common/Garnet.common.csproj | Adds VS threading analyzers package reference. |
| libs/common/Format.cs | Splits endpoint creation into sync + async APIs; removes sync-over-async usages. |
| libs/common/ExceptionInjectionHelper.cs | Renames WaitOnSet -> WaitOnSetAsync; adds sync WaitOnClear spin helper. |
| libs/common/AsyncUtils.cs | Adds centralized blocking helper methods for Task/ValueTask. |
| libs/cluster/Session/RespClusterSlotManagementCommands.cs | Uses blocking helper for epoch bump on network thread. |
| libs/cluster/Session/RespClusterReplicationCommands.cs | Converts replication commands to async manager APIs but blocks on network thread. |
| libs/cluster/Session/RespClusterMigrateCommands.cs | Removes ineffective ConfigureAwait(false) on Task.Run; uses discard pattern. |
| libs/cluster/Session/RespClusterFailoverCommands.cs | Uses blocking helper for epoch transitions and replication offset wait on network thread. |
| libs/cluster/Session/ReplicaOfCommand.cs | Renames network handler method; blocks on async epoch/task suspension appropriately. |
| libs/cluster/Session/MigrateCommand.cs | Uses sync DNS resolve; converts start-migration to async API + blocking wait on network thread. |
| libs/cluster/Session/ClusterSession.cs | Refactors unsafe usage boundaries; makes epoch bump transition async. |
| libs/cluster/Server/Replication/ReplicationManager.cs | Renames replication offset wait to WaitForReplicationOffsetAsync; blocks on replication init path. |
| libs/cluster/Server/Replication/ReplicaOps/ReplicationReplicaAofSync.cs | Updates replay task runner to async method. |
| libs/cluster/Server/Replication/ReplicaOps/ReplicaReplayTask.cs | Converts replay loop from async void to Task; adds ConfigureAwait(false). |
| libs/cluster/Server/Replication/ReplicaOps/ReceiveCheckpointHandler.cs | Replaces async clear-wait with sync spin wait for debug-only injection. |
| libs/cluster/Server/Replication/PrimaryOps/ReplicationPrimaryAofSync.cs | Updates replica sync task invocation to async method. |
| libs/cluster/Server/Replication/PrimaryOps/ReplicaSyncSession.cs | Renames checkpoint send/acquire and related helpers to async; uses ConfigureAwait(false) broadly. |
| libs/cluster/Server/Replication/PrimaryOps/PrimarySync.cs | Converts primary sync entry points to async tuple-returning APIs (success + error payload). |
| libs/cluster/Server/Replication/PrimaryOps/DisklessReplication/ReplicationSyncManager.cs | Renames driver/flush/snapshot helpers to async; adds ConfigureAwait(false) and async cancellation. |
| libs/cluster/Server/Replication/PrimaryOps/DisklessReplication/ReplicationSnapshotIterator.cs | Uses blocking helper for flush waits in scan callbacks. |
| libs/cluster/Server/Replication/PrimaryOps/DisklessReplication/ReplicaSyncSession.cs | Renames flush/sync methods to async; removes sync-over-async patterns in execute/flush. |
| libs/cluster/Server/Replication/PrimaryOps/AofSyncTaskInfo.cs | Renames replica sync task to ReplicaSyncTaskAsync. |
| libs/cluster/Server/Migration/MigrationDriver.cs | Makes migration task start and connection checks async. |
| libs/cluster/Server/Migration/MigrateSessionSlots.cs | Refactors slot migration driver to async; removes unsafe+sync waiting patterns. |
| libs/cluster/Server/Migration/MigrateSessionKeys.cs | Converts KEYS migration flow to async; avoids blocking inside unsafe blocks. |
| libs/cluster/Server/Migration/MigrateSessionKeyAccess.cs | Converts config propagation waits to async-returning method. |
| libs/cluster/Server/Migration/MigrateSessionCommonUtils.cs | Refactors send/flush/retry logic to async-friendly patterns. |
| libs/cluster/Server/Migration/MigrateSession.cs | Makes connection/auth handling async; refactors connection checks. |
| libs/cluster/Server/Migration/MigrateOperation.cs | Converts initialization/transmit flows to async. |
| libs/cluster/Server/Gossip/Gossip.cs | Converts gossip loop and cluster publish forwarding to async APIs; introduces sync fast-path with async fallback. |
| libs/cluster/Server/Gossip/GarnetServerNode.cs | Changes InitializeAsync to ValueTask; refactors gossip call to async implementation. |
| libs/cluster/Server/Gossip/GarnetClusterConnectionStore.cs | Renames connection store methods to async; makes GetOrAddAsync return ValueTask. |
| libs/cluster/Server/Gossip/GarnetClientExtensions.cs | Adds Async suffix to extension methods; adjusts publish parameter passing. |
| libs/cluster/Server/Failover/ReplicaFailoverSession.cs | Renames and async-ifies failover steps; updates gossip and attach flows. |
| libs/cluster/Server/Failover/PrimaryFailoverSession.cs | Renames and async-ifies replica sync checks and failover orchestration. |
| libs/cluster/Server/Failover/FailoverManager.cs | Updates invocations to renamed async failover entry points. |
| libs/cluster/Server/ClusterProvider.cs | Makes epoch bump/transition wait async. |
| libs/cluster/Server/ClusterManagerWorkerState.cs | Converts TryAddReplica to async tuple-returning API; suspends tasks asynchronously. |
| libs/cluster/Server/ClusterManager.cs | Renames cluster config flush background loop to async. |
| libs/cluster/Garnet.cluster.csproj | Adds VS threading analyzers package reference. |
| libs/client/GarnetClientAPI/GarnetClientExecuteAPI.cs | Removes ref Span<byte> parameters from no-response API surface. |
| libs/client/GarnetClient.cs | Introduces sync socket connect path; blocks auth via AsyncUtils.BlockingWait; removes sync Reconnect. |
| libs/client/ClientSession/GarnetClientSession.cs | Introduces sync socket connect path; moves auth to sync execute; adds async connect/reconnect APIs. |
| hosting/Windows/Garnet.worker/Garnet.worker.csproj | Adds VS threading analyzers package reference. |
| Directory.Packages.props | Pins Microsoft.VisualStudio.Threading.Analyzers version centrally. |
| .editorconfig | Enables VSTHRD200 as error and configures related analyzer severities. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
badrishc
reviewed
Apr 24, 2026
badrishc
reviewed
Apr 24, 2026
…duce IsAuthenticated(...) to allow polling for auth completion, which many callers assume
badrishc
approved these changes
Apr 28, 2026
1 task
yuseok-kim-edushare
added a commit
to yuseok-kim-edushare/garnet
that referenced
this pull request
May 2, 2026
- CI failure about VSTHRD002 with related PR microsoft#1714
yuseok-kim-edushare
added a commit
to yuseok-kim-edushare/garnet
that referenced
this pull request
May 2, 2026
- To reflect microsoft#1714 PR's Code Changes : TakeCheckpoint replaced with TakeCheckpointAsync
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.
Doing a pass through Garnet to remove blocking where possible, document where it's required, and prevent regression in the future.
There are broadly three places where blocking is still required:
NetworkprefixMajor changes:
Task-like blocking operations in Garnet proper are moved toAsyncUtilsTask-like returning methods conform to .NET async naming rules now.ConfigureAwait(false)added where missingasync/awaitMicrosoft.VisualStudio.Threadinganalyzers added to flag future violationsTsavorite and Garnet.client were not updated as aggressively to limit breaking changes.
TODO:
.GetAwaiter().GetResult()calls into helpers that justify themAsyncsuffix) violationsdevtargeting version - it's unlikely this can be cherry-picked cleanly, so it'll be non-trivial effortdevversion is #1730