Skip to content

[Proposal] Implement "NoWait" Mechanism for DataBase Distributed Locking #7993

@Sumit6307

Description

@Sumit6307

Check Ahead

  • I have searched the issues of this repository and believe that this is not a duplicate.

  • I am willing to try to fix this bug myself.

Ⅰ. Issue Description

The current DataBaseDistributedLocker implementation in server/src/main/java/org/apache/seata/server/storage/db/lock/DataBaseDistributedLocker.java relies on SELECT ... FOR UPDATE which can block threads until the database lock wait timeout is reached.

There is an explicit TODO in the code at line 150 acknowledging this limitation:
// ignore "Lock wait timeout exceeded; try restarting transaction"
// TODO: need nowait adaptation

In high-concurrency scenarios, this blocking behavior can lead to thread pool exhaustion in the Transaction Coordinator (TC) if database locks are contended but not released quickly. I propose to implement a "NoWait" or "Fast Fail" mechanism for the database distributed locker to improve system resilience.

Ⅱ. Describe what happened

When acquiring a distributed lock using DataBaseDistributedLocker , the system executes a blocking SQL query (SELECT ... FOR UPDATE). If the lock is held by another transaction, the current thread blocks and waits until the database lock timeout occurs (which can be several seconds). This consumes thread resources in the TC and delays the failure response to the client.

Ⅲ. Describe what you expected to happen

The DataBaseDistributedLocker should support a nowait adaptation as suggested in the code comments. When
acquireLock is called, it should attempt to acquire the lock using non-blocking SQL syntax (e.g., NOWAIT, SKIP LOCKED, or valid dialect equivalents). If the lock is unavailable, it should fail immediately ("Fast Fail") instead of blocking the thread, allowing the TC to handle the contention more efficiently (e.g., by retrying later or returning a failure status instantly).

Ⅳ. How to reproduce it (as minimally and precisely as possible)

  1. Configure Seata Server to use db as the lock storage mode.
  2. Start two global transactions that contend for the same resource lock (same xid or resource key).
  3. Have the first transaction hold the global lock for a duration longer than the database lock timeout.
  4. Have the second transaction attempt to acquire the same lock.
  5. Observe that the second transaction's thread is blocked in DataBaseDistributedLocker.acquireLock until the DB timeout triggers.

Minimal yet complete reproducer code (or URL to code): Not applicable (Architectural enhancement proposal).

Ⅴ. Anything else we need to know?

My implementation plan includes:

  1. Refactoring DistributedLockSqlFactory to support dialect-specific NOWAIT syntax (Oracle, PostgreSQL, MySQL 8.0+, etc.).
  2. Updating DataBaseDistributedLocker to use these non-blocking queries.
  3. Handling specific SQLExceptions to distinguish "Resource Busy" from other errors.

Ⅵ. Environment

JDK version: 8/11/17+
Seata client/server version: 2.x
Database version: MySQL 8.0+ / PostgreSQL / Oracle
OS: Windows / Linux / MacOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions