{"record":{"id":"77bc23c46adf435b","repo":"iflytek/astron-agent","slug":"timed-out-acquiring-distributed-lock-please-try-again-later","errorCode":null,"errorMessage":"Timed out acquiring distributed lock, please try again later","messagePattern":"Timed out acquiring distributed lock, please try again later","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"console/backend/commons/src/main/java/com/iflytek/astron/console/commons/data/impl/UserInfoDataServiceImpl.java","lineNumber":177,"sourceCode":"        if (userInfo.getUid() == null) {\n            throw new IllegalArgumentException(\"User UID cannot be null\");\n        }\n\n        // First check: fail fast to avoid unnecessary lock contention\n        Optional<UserInfo> existingUser = findByUid(userInfo.getUid());\n        if (existingUser.isPresent()) {\n            return existingUser.get();\n        }\n\n        String lockKey = \"user:create:uid:\" + userInfo.getUid();\n        RLock lock = redissonClient.getLock(lockKey);\n\n        try {\n            // Attempt to acquire the lock: wait up to 5s, hold up to 10s\n            boolean acquired = lock.tryLock(5, 10, TimeUnit.SECONDS);\n\n            if (!acquired) {\n                throw new IllegalStateException(\"Timed out acquiring distributed lock, please try again later\");\n            }\n\n            try {\n                // Second check: re-validate whether UID exists inside the lock\n                Optional<UserInfo> existingUserInLock = findByUid(userInfo.getUid());\n                if (existingUserInLock.isPresent()) {\n                    return existingUserInLock.get();\n                }\n\n                // Set default values\n                LocalDateTime now = LocalDateTime.now();\n                if (userInfo.getCreateTime() == null) {\n                    userInfo.setCreateTime(now);\n                }\n                if (userInfo.getUpdateTime() == null) {\n                    userInfo.setUpdateTime(now);\n                }\n                if (userInfo.getDeleted() == null) {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/data/impl/UserInfoDataServiceImpl.java#L159-L195","documentation":"createOrGetUser uses a Redisson distributed lock (tryLock with 5s wait / 10s lease) to make the check-then-create idempotent across instances. If the lock cannot be acquired within 5 seconds it throws IllegalStateException('Timed out acquiring distributed lock, please try again later') rather than proceeding unsynchronized.","triggerScenarios":"Many concurrent createOrGetUser calls for the same or contended lock keys; a lock holder stuck longer than 5s (slow DB inside the critical section); Redisson lease expiry/rebalance issues; Redis latency or connectivity problems making tryLock slow.","commonSituations":"Burst of first-login requests for the same new user; DB slow queries inside the locked section pushing hold time near the 10s lease; Redis network hiccups in the cluster; thread dumps showing many threads parked on tryLock.","solutions":["Retry the operation with backoff — the error message explicitly says 'try again later' and the user is usually created by the holder shortly after","Reduce time inside the critical section (the findByUid + insert) so the lock is held briefly","Lower contention: deduplicate concurrent requests per uid at the API layer (cache/single-flight)","Check Redis health/latency and confirm lock waitTime (5s) vs DB operation time is a sane ratio"],"exampleFix":"// before\ntry {\n    boolean acquired = lock.tryLock(5, 10, TimeUnit.SECONDS);\n    if (!acquired) throw new IllegalStateException(\"Timed out acquiring distributed lock...\");\n// after\nboolean acquired = lock.tryLock(5, 10, TimeUnit.SECONDS);\nif (!acquired) {\n    // caller may safely retry: holder likely completed creation\n    Optional<UserInfo> existing = findByUid(userInfo.getUid());\n    if (existing.isPresent()) return existing.get();\n    throw new IllegalStateException(\"Timed out acquiring distributed lock, please try again later\");\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return userInfoService.createOrGetUser(userInfo);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Timed out acquiring distributed lock\")) {\n        Thread.sleep(200);\n        return userInfoService.createOrGetUser(userInfo); // single retry\n    }\n    throw e;\n}","preventionTips":["Retry once after a short delay — the winner usually completes creation","Keep the locked critical section fast (indexed findByUid, quick insert)","Single-flight duplicate concurrent requests for the same uid","Monitor Redis latency; tune tryLock waitTime to exceed worst-case section time"],"tags":["java","distributed-lock","redisson","concurrency","timeout"],"backgroundTag":"request-timeout","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"}