Nacos client library for dynamic service discovery and configuration management in cloud native applications and microservices platforms
—
Distributed locking capabilities for coordination and synchronization across microservices. Supports lock expiration, try-lock operations, and remote lock management with automatic cleanup.
Core distributed locking operations for synchronization across microservices.
public interface LockService {
// Acquire distributed lock (blocking)
Boolean lock(LockInstance instance) throws NacosException;
// Release distributed lock
Boolean unLock(LockInstance instance) throws NacosException;
// Try to acquire lock without blocking (non-blocking)
Boolean remoteTryLock(LockInstance instance) throws NacosException;
// Release lock remotely
Boolean remoteReleaseLock(LockInstance instance) throws NacosException;
// Shutdown the lock service
void shutdown() throws NacosException;
}import com.alibaba.nacos.api.lock.LockService;
import com.alibaba.nacos.api.lock.NacosLockFactory;
import com.alibaba.nacos.api.lock.model.LockInstance;
import com.alibaba.nacos.api.exception.NacosException;
// Create lock service
Properties props = new Properties();
props.setProperty("serverAddr", "localhost:8848");
LockService lockService = NacosLockFactory.createLockService(props);
// Create lock instance
LockInstance lockInstance = new LockInstance();
lockInstance.setKey("order-processing-lock");
lockInstance.setExpiredTime(30000L); // 30 seconds in milliseconds
try {
// Acquire lock
Boolean acquired = lockService.lock(lockInstance);
if (acquired) {
System.out.println("Lock acquired successfully");
// Perform critical section operations
processOrder();
} else {
System.out.println("Failed to acquire lock");
}
} finally {
// Always release lock in finally block
lockService.unLock(lockInstance);
}Try-lock operations that don't block if the lock is unavailable.
// Non-blocking lock attempt
LockInstance lockInstance = new LockInstance();
lockInstance.setKey("cache-update-lock");
lockInstance.setExpiredTime(60000L); // 60 seconds in milliseconds
// Try to acquire lock without blocking
Boolean acquired = lockService.remoteTryLock(lockInstance);
if (acquired) {
try {
// Perform cache update
updateCache();
} finally {
// Release lock
lockService.remoteReleaseLock(lockInstance);
}
} else {
System.out.println("Another process is updating cache, skipping...");
}Locks with built-in expiration to prevent deadlocks from process failures.
// Lock with automatic expiration (prevents deadlocks)
String lockKey = "database-migration-lock";
String lockValue = "migration-" + UUID.randomUUID().toString();
// Lock expires after 300 seconds (5 minutes)
boolean acquired = lockService.lock(lockKey, lockValue, 300);
if (acquired) {
try {
// Perform long-running database migration
runDatabaseMigration();
} catch (Exception e) {
System.err.println("Migration failed: " + e.getMessage());
// Lock will automatically expire if process crashes
} finally {
// Explicitly release lock when done
lockService.unLock(lockKey, lockValue);
}
}Common patterns for distributed coordination using locks.
public class OrderProcessor {
private final LockService lockService;
private final String instanceId;
public OrderProcessor(LockService lockService) {
this.lockService = lockService;
this.instanceId = "processor-" + InetAddress.getLocalHost().getHostName();
}
public void processOrderBatch(List<Order> orders) throws NacosException {
String lockKey = "order-batch-processing";
// Ensure only one instance processes orders at a time
boolean acquired = lockService.lock(lockKey, instanceId, 120); // 2 minutes
if (acquired) {
try {
System.out.println("Processing " + orders.size() + " orders...");
for (Order order : orders) {
processOrder(order);
}
System.out.println("Batch processing completed");
} finally {
lockService.unLock(lockKey, instanceId);
}
} else {
System.out.println("Another instance is processing orders");
}
}
}public class LeaderElection {
private final LockService lockService;
private final String nodeId;
private volatile boolean isLeader = false;
public LeaderElection(LockService lockService, String nodeId) {
this.lockService = lockService;
this.nodeId = nodeId;
}
public void tryBecomeLeader() {
String leaderLock = "cluster-leader-election";
try {
// Try to become leader (non-blocking)
boolean becameLeader = lockService.remoteTryLock(leaderLock, nodeId, 60);
if (becameLeader && !isLeader) {
isLeader = true;
System.out.println("Node " + nodeId + " became leader");
startLeaderTasks();
} else if (!becameLeader && isLeader) {
isLeader = false;
System.out.println("Node " + nodeId + " lost leadership");
stopLeaderTasks();
}
} catch (NacosException e) {
System.err.println("Leader election failed: " + e.getMessage());
}
}
public void resignLeadership() {
if (isLeader) {
try {
lockService.remoteReleaseLock("cluster-leader-election", nodeId);
isLeader = false;
stopLeaderTasks();
} catch (NacosException e) {
System.err.println("Failed to resign leadership: " + e.getMessage());
}
}
}
}public class ResourcePoolManager {
private final LockService lockService;
private final String poolName;
public ResourcePoolManager(LockService lockService, String poolName) {
this.lockService = lockService;
this.poolName = poolName;
}
public Resource acquireResource(String resourceId) throws NacosException {
String lockKey = poolName + "-resource-" + resourceId;
String lockValue = "consumer-" + Thread.currentThread().getId();
// Try to acquire resource for 30 seconds
boolean acquired = lockService.remoteTryLock(lockKey, lockValue, 30);
if (acquired) {
return new Resource(resourceId, () -> {
try {
lockService.remoteReleaseLock(lockKey, lockValue);
} catch (NacosException e) {
System.err.println("Failed to release resource: " + e.getMessage());
}
});
} else {
throw new ResourceUnavailableException("Resource " + resourceId + " is in use");
}
}
}public class LockInstance implements Serializable {
private String key;
private Long expiredTime;
private Map<String, ? extends Serializable> params;
private String lockType;
// Constructors
public LockInstance();
public LockInstance(String key, Long expiredTime, String lockType);
// Lock identification
public String getKey();
public void setKey(String key);
public String getLockType();
public void setLockType(String lockType);
// Expiration management
public Long getExpiredTime();
public void setExpiredTime(Long expiredTime);
// Additional parameters
public Map<String, ? extends Serializable> getParams();
public void setParams(Map<String, ? extends Serializable> params);
// Utility methods
public Boolean lock(LockService lockService) throws NacosException;
public Boolean unLock(LockService lockService) throws NacosException;
}public enum LockOperationEnum {
LOCK("lock"),
UNLOCK("unlock"),
TRY_LOCK("tryLock"),
RELEASE_LOCK("releaseLock");
private final String operation;
LockOperationEnum(String operation) {
this.operation = operation;
}
public String getOperation();
}// Lock-specific property keys
public class LockPropertyKeyConst {
// Connection settings
public static final String LOCK_SERVER_ADDR = "lockServerAddr";
public static final String LOCK_NAMESPACE = "lockNamespace";
// Timeout settings
public static final String LOCK_TIMEOUT = "lockTimeout";
public static final String LOCK_RETRY_INTERVAL = "lockRetryInterval";
public static final String LOCK_MAX_RETRY = "lockMaxRetry";
// Default expiration
public static final String DEFAULT_LOCK_EXPIRATION = "defaultLockExpiration";
// Performance tuning
public static final String LOCK_THREAD_POOL_SIZE = "lockThreadPoolSize";
public static final String LOCK_HEARTBEAT_INTERVAL = "lockHeartbeatInterval";
}// Lock-specific exceptions
public class LockException extends NacosException {
public static final int LOCK_ALREADY_HELD = 10001;
public static final int LOCK_NOT_FOUND = 10002;
public static final int LOCK_EXPIRED = 10003;
public static final int LOCK_INVALID_OWNER = 10004;
public LockException(int errCode, String errMsg);
public LockException(int errCode, String errMsg, Throwable cause);
}Use descriptive, hierarchical lock keys to avoid conflicts:
// Good: descriptive hierarchy
"order-processing-batch-daily"
"cache-update-user-profiles"
"database-migration-v2.1"
"leader-election-notification-service"
// Bad: generic names
"lock1"
"process"
"update"Use unique, identifiable lock values:
// Include instance/thread identification
String lockValue = instanceId + "-" + Thread.currentThread().getId() + "-" + System.currentTimeMillis();
// Or use UUID for uniqueness
String lockValue = UUID.randomUUID().toString();Set appropriate expiration times based on operation duration:
// Short operations (few seconds)
lockService.lock(lockKey, lockValue, 30);
// Medium operations (minutes)
lockService.lock(lockKey, lockValue, 300);
// Long operations (hours) - consider breaking into smaller chunks
lockService.lock(lockKey, lockValue, 3600);Always handle lock failures gracefully:
try {
boolean acquired = lockService.lock(lockKey, lockValue, 60);
if (!acquired) {
// Handle inability to acquire lock
scheduleRetry();
return;
}
// Perform critical section
performCriticalOperation();
} catch (NacosException e) {
// Handle network or server errors
handleLockError(e);
} finally {
// Always attempt to release lock
try {
lockService.unLock(lockKey, lockValue);
} catch (NacosException e) {
// Log but don't fail - lock will expire
logger.warn("Failed to release lock: " + e.getMessage());
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-alibaba-nacos--nacos-client