package tech.powerjob.server.core.lock;
|
|
import tech.powerjob.common.utils.CommonUtils;
|
import tech.powerjob.common.utils.NetUtils;
|
import tech.powerjob.server.extension.LockService;
|
import tech.powerjob.server.persistence.remote.model.OmsLockDO;
|
import tech.powerjob.server.persistence.remote.repository.OmsLockRepository;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.stereotype.Service;
|
|
/**
|
* 基于数据库实现的分布式锁
|
*
|
* @author tjq
|
* @since 2020/4/5
|
*/
|
@Slf4j
|
@Service
|
public class DatabaseLockService implements LockService {
|
|
private final String ownerIp;
|
|
private final OmsLockRepository omsLockRepository;
|
|
@Autowired
|
public DatabaseLockService(OmsLockRepository omsLockRepository) {
|
|
this.ownerIp = NetUtils.getLocalHost();
|
this.omsLockRepository = omsLockRepository;
|
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
int num = omsLockRepository.deleteByOwnerIP(ownerIp);
|
log.info("[DatabaseLockService] execute shutdown hook, release all lock(owner={},num={})", ownerIp, num);
|
}));
|
}
|
|
@Override
|
public boolean tryLock(String name, long maxLockTime) {
|
|
OmsLockDO newLock = new OmsLockDO(name, ownerIp, maxLockTime);
|
try {
|
omsLockRepository.saveAndFlush(newLock);
|
return true;
|
} catch (DataIntegrityViolationException ignore) {
|
} catch (Exception e) {
|
log.warn("[DatabaseLockService] write lock to database failed, lockName = {}.", name, e);
|
}
|
|
OmsLockDO omsLockDO = omsLockRepository.findByLockName(name);
|
long lockedMillions = System.currentTimeMillis() - omsLockDO.getGmtCreate().getTime();
|
|
// 锁超时,强制释放锁并重新尝试获取
|
if (lockedMillions > omsLockDO.getMaxLockTime()) {
|
|
log.warn("[DatabaseLockService] The lock[{}] already timeout, will be unlocked now.", omsLockDO);
|
unlock(name);
|
return tryLock(name, maxLockTime);
|
}
|
return false;
|
}
|
|
@Override
|
public void unlock(String name) {
|
|
try {
|
CommonUtils.executeWithRetry0(() -> omsLockRepository.deleteByLockName(name));
|
}catch (Exception e) {
|
log.error("[DatabaseLockService] unlock {} failed.", name, e);
|
}
|
}
|
|
}
|