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
- 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
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
- 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
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
- REDIS_CONNECTION_ERROR
- ExecuteShutdown unlock threw exception. key=
- Timed out acquiring distributed lock, please try again later
- Distributed lock acquisition timeout, please try again later
- ACQUIRE_TIMEOUT
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)