Skip to content

Race Condition in SQL Server Distributed Cache with Transactional Operations #60923

Open
@RexMagi

Description

@RexMagi

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

ASP.NET Core's SqlDistributedCache exhibits problematic behavior within database transactions. The background process, ScanForExpiredItemsIfRequired, responsible for removing expired cache entries, can execute after the transaction commits. This results in errors due to SQL Server's limitation of concurrent data source access following transaction completion.

The cause is the independent execution of ScanForExpiredItemsIfRequired relative to user transactions. Triggered post-cache read/write, and subject to ExpiredItemsDeletionInterval, it initiates cleanup on a background thread, disconnecting it from the transaction's lifecycle.

This lack of transactional awareness yields problems. The background thread's attempt to delete expired cache rows post-commit can generate random errors. SQL Server may throw exceptions due to an invalid context. Contention can also arise between cleanup and application code; concurrent operations result in resource conflicts. SQL Server's concurrency mechanisms may block or throw errors, impacting performance.

Expected Behavior

Here's how the SqlDistributedCache should behave:

  • Transaction Isolation: The background cleanup of expired items must operate independently of any active database transactions. It should not attempt to use the same database context as a transaction that has already been committed.

  • Dedicated Resources: The cleanup process should use its own dedicated database connection and, if necessary, its own transaction. This ensures it doesn't interfere with the main application's database operations.

  • Preventing Contention: The design must prevent the cleanup process from causing locking or blocking that could impact the application's read and write operations on the cache.

  • Error Prevention: The ScanForExpiredItemsIfRequired method should be modified to avoid attempting to delete expired items within a committed transaction's context, eliminating the current SQL Server errors.

Essentially, the cleanup needs to be a self-contained operation, completely separate from the application's transactional flow.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

No response

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-cachingIncludes: StackExchangeRedis and SqlServer distributed caches

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions