{"record":{"id":"9bd1e2c496de14df","repo":"YunaiV/ruoyi-vue-pro","slug":"423","errorCode":"423","errorMessage":"请求失败，请稍后重试","messagePattern":"请求失败，请稍后重试","errorType":"exception","errorClass":"ServiceException","httpStatus":null,"severity":"warning","filePath":"yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java","lineNumber":19,"sourceCode":"package cn.iocoder.yudao.framework.lock4j.core;\n\nimport cn.iocoder.yudao.framework.common.exception.ServiceException;\nimport cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;\nimport com.baomidou.lock.LockFailureStrategy;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.lang.reflect.Method;\n\n/**\n * 自定义获取锁失败策略，抛出 {@link ServiceException} 异常\n */\n@Slf4j\npublic class DefaultLockFailureStrategy implements LockFailureStrategy {\n\n    @Override\n    public void onLockFailure(String key, Method method, Object[] arguments) {\n        log.debug(\"[onLockFailure][线程:{} 获取锁失败，key:{} 获取失败:{} ]\", Thread.currentThread().getName(), key, arguments);\n        throw new ServiceException(GlobalErrorCodeConstants.LOCKED);\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":22,"githubUrl":"https://github.com/YunaiV/ruoyi-vue-pro/blob/0418084e222612af2fc1141f566af454f9236ab1/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java#L1-L22","documentation":"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.","triggerScenarios":"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.","commonSituations":"User double-clicks a long-running action; a job runs in parallel on multiple nodes; lock key is too coarse so unrelated calls contend.","solutions":["Reduce contention: narrow the @Lock4j compose key to the specific business entity.","Increase acquireTimeout / expireTime on @Lock4j so the caller waits briefly instead of failing fast.","Ensure long-running locked work completes or the lock TTL is appropriate so stale locks expire.","If failure is acceptable UX, catch ServiceException(code==423) and show a friendly retry message."],"exampleFix":"// before: coarse lock causes contention\n@Lock4j(keys = {\"#user.id\"})\n// after: lock the specific resource\n@Lock4j(keys = {\"#orderId\"}, acquireTimeout = 3000, expire = 10000)","handlingStrategy":"try-catch","validationCode":"boolean acquired = redissonLock.tryLock(key, wait, lease, unit);\nif (!acquired) throw new ServiceException(LOCKED);","typeGuard":"null","tryCatchPattern":"try { method.invoke(); }\ncatch (ServiceException e) { if (e.getCode()==423) { backoffAndRetry(); return; } throw e; }","preventionTips":["Narrow the @Lock4j key to the specific entity","Set an acquireTimeout so callers wait briefly","Ensure locked work completes or TTL is appropriate"],"tags":["yudao","lock4j","redis","distributed-lock"],"backgroundTag":null,"analyzedSha":"0418084e222612af2fc1141f566af454f9236ab1","analyzedAt":"2026-08-14T00:56:18.412Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}