{"record":{"id":"82f1161a312521f7","repo":"iflytek/astron-agent","slug":"release-failed","errorCode":"RELEASE_FAILED","errorMessage":"Lock release failed: ","messagePattern":"Lock release failed: ","errorType":"exception","errorClass":"DistributedLockException","httpStatus":null,"severity":"error","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/aspect/DistributedLockAspect.java","lineNumber":130,"sourceCode":"     */\n    private DistributedLockException createLockException(String lockKey, DistributedLock distributedLock, InterruptedException e) {\n        return new DistributedLockException(lockKey, DistributedLockException.LockErrorType.ACQUIRE_TIMEOUT, \"Thread interrupted while acquiring lock\", e);\n    }\n\n    /**\n     * Release lock safely\n     */\n    private void releaseLockSafely(DistributedLock distributedLock, String lockKey, RLock lock, boolean acquired, long startTime) {\n        if (acquired && lock.isHeldByCurrentThread()) {\n            try {\n                lock.unlock();\n                if (distributedLock.enableLog()) {\n                    long totalTime = System.currentTimeMillis() - startTime;\n                    log.info(\"Successfully released distributed lock: key={}, totalTime={}ms\", lockKey, totalTime);\n                }\n            } catch (Exception e) {\n                log.error(\"Failed to release distributed lock: key={}, message={}\", lockKey, e.getMessage(), e);\n                throw new DistributedLockException(lockKey, DistributedLockException.LockErrorType.RELEASE_FAILED, \"Lock release failed: \" + e.getMessage(), e);\n            }\n        }\n    }\n\n    /**\n     * Parse lock key, supports SpEL expressions\n     */\n    private String parseLockKey(String keyExpression, ProceedingJoinPoint point) {\n        try {\n            // This check is a fast path for strings without any dynamic content\n            if (!keyExpression.contains(\"#{\")) {\n                return keyExpression;\n            }\n\n            MethodSignature signature = (MethodSignature) point.getSignature();\n            Method method = signature.getMethod();\n            Object[] args = point.getArgs();\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/aspect/DistributedLockAspect.java#L112-L148","documentation":"DistributedLockAspect wraps the Redisson lock unlock call in try/catch and throws DistributedLockException with LockErrorType.RELEASE_FAILED when unlocking raises any exception. The lock may remain held in Redis until it expires via leaseTime, potentially blocking other threads that need the same key.","triggerScenarios":"releaseLockSafely calls lock.unlock() and the Redisson/Redis call throws (connection dropped, lock already expired and owned by another thread, Redisson instance shut down).","commonSituations":"Method execution exceeded leaseTime so the lock expired and unlock throws IllegalMonitorState; Redis connection blip or failover mid-request; Redisson client closed during application shutdown.","solutions":["Check log line 'Failed to release distributed lock: key=...' for the underlying exception","Increase leaseTime (or use watchdog/longer lease) so business methods finish before the lock expires","Verify Redis connectivity/stability and pool settings; check for failover events","Ensure unlock happens in finally only on the thread that acquired the lock","On RELEASE_FAILED, rely on lock TTL for cleanup and add retry/backoff on the business side"],"exampleFix":"// before\n@DistributedLock(key = \"'job:' + #id\")   // default lease too short\npublic void process(Long id) { slowWork(id); }\n// after\n@DistributedLock(key = \"'job:' + #id\", leaseTime = 300, timeUnit = TimeUnit.SECONDS)\npublic void process(Long id) { slowWork(id); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return proceed(); } catch (DistributedLockException e) { if (e.getErrorType() == LockErrorType.RELEASE_FAILED) { log.warn(\"lock {} not cleanly released, relying on TTL\", e.getLockKey()); } throw e; }","preventionTips":["Set leaseTime comfortably larger than worst-case method runtime","Only unlock from the owning thread","Monitor Redis connection stability","Treat RELEASE_FAILED as transient — TTL will clean up"],"tags":["redis","distributed-lock","redisson","unlock"],"backgroundTag":"lock-release-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}