YunaiV/ruoyi-vue-pro · warning · ServiceException

423

423

Error message

请求失败,请稍后重试

What it means

DefaultLockFailureStrategy implements lock4j's LockFailureStrategy.onLockFailure. When a @Lock4j method cannot acquire the distributed lock (another holder owns it), it throws ServiceException(LOCKED, code 423, default '请求失败,请稍后重试'). This is by design: the request was rejected because a concurrent operation holds the lock.

Source

Thrown at yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java:19

package cn.iocoder.yudao.framework.lock4j.core;

import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.baomidou.lock.LockFailureStrategy;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * 自定义获取锁失败策略,抛出 {@link ServiceException} 异常
 */
@Slf4j
public class DefaultLockFailureStrategy implements LockFailureStrategy {

    @Override
    public void onLockFailure(String key, Method method, Object[] arguments) {
        log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取失败:{} ]", Thread.currentThread().getName(), key, arguments);
        throw new ServiceException(GlobalErrorCodeConstants.LOCKED);
    }
}

View on GitHub (pinned to 0418084e22)

Solutions

  1. Reduce contention: narrow the @Lock4j compose key to the specific business entity.
  2. Increase acquireTimeout / expireTime on @Lock4j so the caller waits briefly instead of failing fast.
  3. Ensure long-running locked work completes or the lock TTL is appropriate so stale locks expire.
  4. If failure is acceptable UX, catch ServiceException(code==423) and show a friendly retry message.

Example fix

// before: coarse lock causes contention
@Lock4j(keys = {"#user.id"})
// after: lock the specific resource
@Lock4j(keys = {"#orderId"}, acquireTimeout = 3000, expire = 10000)
Defensive patterns

Strategy: try-catch

Validate before calling

boolean acquired = redissonLock.tryLock(key, wait, lease, unit);
if (!acquired) throw new ServiceException(LOCKED);

Type guard

null

Try / catch

try { method.invoke(); }
catch (ServiceException e) { if (e.getCode()==423) { backoffAndRetry(); return; } throw e; }

Prevention

When it happens

Trigger: Two concurrent invocations of the same @Lock4j method with the same lock key; a previous invocation is slow and still holds the lock; a crashed holder left a lock that has not yet TTL-expired.

Common situations: User double-clicks a long-running action; a job runs in parallel on multiple nodes; lock key is too coarse so unrelated calls contend.

Related errors


AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14). Data as JSON: /api/errors/9bd1e2c496de14df. Report an issue: GitHub.