YunaiV/yudao-cloud · warning · ServiceException

423

423

Error message

请求失败,请稍后重试

What it means

When a @Lock4j/@RateLimiter-protected method cannot acquire its distributed lock, LockFailureStrategy fires. The framework's default implementation throws ServiceException with the global LOCKED error (HTTP 423-ish semantic: resource locked). The strategy bean can be replaced to customize behavior.

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 477be9dd49)

Solutions

  1. Retry after a short delay or surface '操作正在执行中,请稍后再试' to the user.
  2. Ensure lock keys are scoped narrowly (include entity id) so unrelated operations don't contend.
  3. Set a reasonable expire/retry configuration on @Lock4j (acquireTimeout, expire) instead of failing fast.
  4. If waiting is acceptable, register a custom LockFailureStrategy that retries or blocks instead of throwing.

Example fix

// before
lock4j.tryLockAndExecute(() -> service.rebuildIndex()); // throws on contention

// after
try {
    lock4j.tryLockAndExecute(() -> service.rebuildIndex());
} catch (ServiceException e) {
    if (GlobalErrorCodeConstants.LOCKED.getCode().equals(e.getCode())) {
        return Result.error("任务正在执行,请稍后再试");
    }
    throw e;
}
Defensive patterns

Strategy: retry

Try / catch

try {
    service.doLockedOp(id);
} catch (ServiceException e) {
    if (GlobalErrorCodeConstants.LOCKED.getCode().equals(e.getCode())) {
        scheduleRetryIn(Duration.ofSeconds(5)); // or inform user
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: Two threads/users invoke a method guarded by lock4j (same key) concurrently; the first holds the lock (e.g. during a long batch operation) and the second's acquire fails immediately, invoking DefaultLockFailureStrategy.onLockFailure.

Common situations: Scheduled jobs and manual triggers overlapping on the same lock; concurrent admin operations on the same entity; locks not released after a crash until expire-time passes (lock leak); long transactions exceeding the lock acquire timeout.

Related errors


AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14). Data as JSON: /api/errors/8c82ace88e409250. Report an issue: GitHub.