iflytek/astron-agent · error · DistributedLockException

RELEASE_FAILED

RELEASE_FAILED

Error message

Lock release failed: 

What it means

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.

Solutions

  1. Check log line 'Failed to release distributed lock: key=...' for the underlying exception
  2. Increase leaseTime (or use watchdog/longer lease) so business methods finish before the lock expires
  3. Verify Redis connectivity/stability and pool settings; check for failover events
  4. Ensure unlock happens in finally only on the thread that acquired the lock
  5. On RELEASE_FAILED, rely on lock TTL for cleanup and add retry/backoff on the business side

Example fix

// before
@DistributedLock(key = "'job:' + #id")   // default lease too short
public void process(Long id) { slowWork(id); }
// after
@DistributedLock(key = "'job:' + #id", leaseTime = 300, timeUnit = TimeUnit.SECONDS)
public void process(Long id) { slowWork(id); }
Defensive patterns

Strategy: try-catch

Try / catch

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; }

Prevention

When it happens

Trigger: releaseLockSafely calls lock.unlock() and the Redisson/Redis call throws (connection dropped, lock already expired and owned by another thread, Redisson instance shut down).

Common situations: 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.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/82f1161a312521f7. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/hub/src/main/java/com/iflytek/astron/console/hub/aspect/DistributedLockAspect.java:130

     */
    private DistributedLockException createLockException(String lockKey, DistributedLock distributedLock, InterruptedException e) {
        return new DistributedLockException(lockKey, DistributedLockException.LockErrorType.ACQUIRE_TIMEOUT, "Thread interrupted while acquiring lock", e);
    }

    /**
     * Release lock safely
     */
    private void releaseLockSafely(DistributedLock distributedLock, String lockKey, RLock lock, boolean acquired, long startTime) {
        if (acquired && lock.isHeldByCurrentThread()) {
            try {
                lock.unlock();
                if (distributedLock.enableLog()) {
                    long totalTime = System.currentTimeMillis() - startTime;
                    log.info("Successfully released distributed lock: key={}, totalTime={}ms", lockKey, totalTime);
                }
            } catch (Exception e) {
                log.error("Failed to release distributed lock: key={}, message={}", lockKey, e.getMessage(), e);
                throw new DistributedLockException(lockKey, DistributedLockException.LockErrorType.RELEASE_FAILED, "Lock release failed: " + e.getMessage(), e);
            }
        }
    }

    /**
     * Parse lock key, supports SpEL expressions
     */
    private String parseLockKey(String keyExpression, ProceedingJoinPoint point) {
        try {
            // This check is a fast path for strings without any dynamic content
            if (!keyExpression.contains("#{")) {
                return keyExpression;
            }

            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            Object[] args = point.getArgs();

View on GitHub (pinned to 5e758547a8)