feat: 2.6.0
1. 修复分布式锁异常问题
This commit is contained in:
parent
145d397b10
commit
fa4eee8842
@ -45,6 +45,6 @@ public enum JobOperationReasonEnum {
|
|||||||
*/
|
*/
|
||||||
public static final List<Integer> WORKFLOW_SUCCESSOR_SKIP_EXECUTION = Arrays.asList(
|
public static final List<Integer> WORKFLOW_SUCCESSOR_SKIP_EXECUTION = Arrays.asList(
|
||||||
WORKFLOW_NODE_NO_REQUIRED.getReason(), WORKFLOW_DECISION_FAILED.getReason(),
|
WORKFLOW_NODE_NO_REQUIRED.getReason(), WORKFLOW_DECISION_FAILED.getReason(),
|
||||||
WORKFLOW_CONDITION_NODE_EXECUTION_ERROR.reason);
|
WORKFLOW_CONDITION_NODE_EXECUTION_ERROR.getReason());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package com.aizuda.easy.retry.server.common.lock;
|
package com.aizuda.easy.retry.server.common.lock;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.aizuda.easy.retry.common.core.context.SpringContext;
|
||||||
import com.aizuda.easy.retry.server.common.cache.CacheLockRecord;
|
import com.aizuda.easy.retry.server.common.cache.CacheLockRecord;
|
||||||
import com.aizuda.easy.retry.server.common.dto.LockConfig;
|
import com.aizuda.easy.retry.server.common.dto.LockConfig;
|
||||||
import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
|
import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
@ -31,7 +33,6 @@ public abstract class AbstractLockProvider implements LockProvider {
|
|||||||
|
|
||||||
LockManager.setLockAtLeast(lockAtLeast);
|
LockManager.setLockAtLeast(lockAtLeast);
|
||||||
LockManager.setLockAtMost(lockAtMost);
|
LockManager.setLockAtMost(lockAtMost);
|
||||||
|
|
||||||
boolean tryToCreateLockRecord = !CacheLockRecord.lockRecordRecentlyCreated(lockName);
|
boolean tryToCreateLockRecord = !CacheLockRecord.lockRecordRecentlyCreated(lockName);
|
||||||
if (tryToCreateLockRecord) {
|
if (tryToCreateLockRecord) {
|
||||||
if (doLock(lockConfig)) {
|
if (doLock(lockConfig)) {
|
||||||
@ -42,7 +43,7 @@ public abstract class AbstractLockProvider implements LockProvider {
|
|||||||
CacheLockRecord.addLockRecord(lockName);
|
CacheLockRecord.addLockRecord(lockName);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean lock = false;
|
boolean lock;
|
||||||
try {
|
try {
|
||||||
lock = doLockAfter(lockConfig);
|
lock = doLockAfter(lockConfig);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -51,10 +52,6 @@ public abstract class AbstractLockProvider implements LockProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
|
||||||
if (!lock) {
|
|
||||||
LockManager.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lock;
|
return lock;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.aizuda.easy.retry.server.common.lock.persistence;
|
package com.aizuda.easy.retry.server.common.lock.persistence;
|
||||||
|
|
||||||
|
import com.aizuda.easy.retry.common.core.context.SpringContext;
|
||||||
import com.aizuda.easy.retry.common.log.EasyRetryLog;
|
import com.aizuda.easy.retry.common.log.EasyRetryLog;
|
||||||
import com.aizuda.easy.retry.server.common.Lifecycle;
|
import com.aizuda.easy.retry.server.common.Lifecycle;
|
||||||
import com.aizuda.easy.retry.server.common.cache.CacheLockRecord;
|
import com.aizuda.easy.retry.server.common.cache.CacheLockRecord;
|
||||||
@ -18,7 +19,12 @@ import org.springframework.dao.DuplicateKeyException;
|
|||||||
import org.springframework.jdbc.BadSqlGrammarException;
|
import org.springframework.jdbc.BadSqlGrammarException;
|
||||||
import org.springframework.jdbc.UncategorizedSQLException;
|
import org.springframework.jdbc.UncategorizedSQLException;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.TransactionSystemException;
|
import org.springframework.transaction.TransactionSystemException;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -48,76 +54,90 @@ public class JdbcLockProvider implements LockStorage, Lifecycle {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createLock(LockConfig lockConfig) {
|
public boolean createLock(LockConfig lockConfig) {
|
||||||
try {
|
TransactionTemplate transactionTemplate = SpringContext.getBean(TransactionTemplate.class);
|
||||||
LocalDateTime now = lockConfig.getCreateDt();
|
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
|
||||||
DistributedLock distributedLock = new DistributedLock();
|
return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
|
||||||
distributedLock.setName(lockConfig.getLockName());
|
try {
|
||||||
distributedLock.setLockedBy(ServerRegister.CURRENT_CID);
|
LocalDateTime now = lockConfig.getCreateDt();
|
||||||
distributedLock.setLockedAt(now);
|
DistributedLock distributedLock = new DistributedLock();
|
||||||
distributedLock.setLockUntil(lockConfig.getLockAtMost());
|
distributedLock.setName(lockConfig.getLockName());
|
||||||
distributedLock.setCreateDt(now);
|
distributedLock.setLockedBy(ServerRegister.CURRENT_CID);
|
||||||
distributedLock.setUpdateDt(now);
|
distributedLock.setLockedAt(now);
|
||||||
return distributedLockMapper.insert(distributedLock) > 0;
|
distributedLock.setLockUntil(lockConfig.getLockAtMost());
|
||||||
} catch (DuplicateKeyException | ConcurrencyFailureException | TransactionSystemException e) {
|
distributedLock.setCreateDt(now);
|
||||||
return false;
|
distributedLock.setUpdateDt(now);
|
||||||
} catch (DataIntegrityViolationException | BadSqlGrammarException | UncategorizedSQLException e) {
|
return distributedLockMapper.insert(distributedLock) > 0;
|
||||||
EasyRetryLog.LOCAL.error("Unexpected exception. lockName:[{}]", lockConfig.getLockName(), e);
|
} catch (DuplicateKeyException | ConcurrencyFailureException | TransactionSystemException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
} catch (DataIntegrityViolationException | BadSqlGrammarException | UncategorizedSQLException e) {
|
||||||
|
EasyRetryLog.LOCAL.error("Unexpected exception. lockName:[{}]", lockConfig.getLockName(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean renewal(LockConfig lockConfig) {
|
public boolean renewal(LockConfig lockConfig) {
|
||||||
LocalDateTime now = lockConfig.getCreateDt();
|
TransactionTemplate transactionTemplate = SpringContext.getBean(TransactionTemplate.class);
|
||||||
DistributedLock distributedLock = new DistributedLock();
|
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
|
||||||
distributedLock.setLockedBy(ServerRegister.CURRENT_CID);
|
return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
|
||||||
distributedLock.setLockedAt(now);
|
LocalDateTime now = lockConfig.getCreateDt();
|
||||||
distributedLock.setLockUntil(lockConfig.getLockAtMost());
|
DistributedLock distributedLock = new DistributedLock();
|
||||||
distributedLock.setName(lockConfig.getLockName());
|
distributedLock.setLockedBy(ServerRegister.CURRENT_CID);
|
||||||
try {
|
distributedLock.setLockedAt(now);
|
||||||
return distributedLockMapper.update(distributedLock, new LambdaUpdateWrapper<DistributedLock>()
|
distributedLock.setLockUntil(lockConfig.getLockAtMost());
|
||||||
.eq(DistributedLock::getName, lockConfig.getLockName())
|
distributedLock.setName(lockConfig.getLockName());
|
||||||
.le(DistributedLock::getLockUntil, now)) > 0;
|
try {
|
||||||
} catch (ConcurrencyFailureException | DataIntegrityViolationException | TransactionSystemException |
|
return distributedLockMapper.update(distributedLock, new LambdaUpdateWrapper<DistributedLock>()
|
||||||
UncategorizedSQLException e) {
|
.eq(DistributedLock::getName, lockConfig.getLockName())
|
||||||
return false;
|
.le(DistributedLock::getLockUntil, now)) > 0;
|
||||||
}
|
} catch (ConcurrencyFailureException | DataIntegrityViolationException | TransactionSystemException |
|
||||||
|
UncategorizedSQLException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean releaseLockWithDelete(String lockName) {
|
public boolean releaseLockWithDelete(String lockName) {
|
||||||
|
TransactionTemplate transactionTemplate = SpringContext.getBean(TransactionTemplate.class);
|
||||||
for (int i = 0; i < 10; i++) {
|
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
|
||||||
try {
|
return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
|
||||||
CacheLockRecord.remove(lockName);
|
for (int i = 0; i < 10; i++) {
|
||||||
return distributedLockMapper.delete(new LambdaUpdateWrapper<DistributedLock>()
|
try {
|
||||||
.eq(DistributedLock::getName, lockName)) > 0;
|
return distributedLockMapper.delete(new LambdaUpdateWrapper<DistributedLock>()
|
||||||
} catch (Exception e) {
|
.eq(DistributedLock::getName, lockName)) > 0;
|
||||||
EasyRetryLog.LOCAL.error("unlock error. retrying attempt [{}] ", i, e);
|
} catch (Exception e) {
|
||||||
|
EasyRetryLog.LOCAL.error("unlock error. retrying attempt [{}] ", i, e);
|
||||||
|
} finally {
|
||||||
|
CacheLockRecord.remove(lockName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
}));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean releaseLockWithUpdate(String lockName, LocalDateTime lockAtLeast) {
|
public boolean releaseLockWithUpdate(String lockName, LocalDateTime lockAtLeast) {
|
||||||
|
TransactionTemplate transactionTemplate = SpringContext.getBean(TransactionTemplate.class);
|
||||||
|
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
try {
|
try {
|
||||||
DistributedLock distributedLock = new DistributedLock();
|
DistributedLock distributedLock = new DistributedLock();
|
||||||
distributedLock.setLockedBy(ServerRegister.CURRENT_CID);
|
distributedLock.setLockedBy(ServerRegister.CURRENT_CID);
|
||||||
distributedLock.setLockUntil(now.isBefore(lockAtLeast) ? lockAtLeast : now);
|
distributedLock.setLockUntil(now.isBefore(lockAtLeast) ? lockAtLeast : now);
|
||||||
return distributedLockMapper.update(distributedLock, new LambdaUpdateWrapper<DistributedLock>()
|
return distributedLockMapper.update(distributedLock, new LambdaUpdateWrapper<DistributedLock>()
|
||||||
.eq(DistributedLock::getName, lockName)) > 0;
|
.eq(DistributedLock::getName, lockName)) > 0;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
EasyRetryLog.LOCAL.error("unlock error. retrying attempt [{}] ", i, e);
|
EasyRetryLog.LOCAL.error("unlock error. retrying attempt [{}] ", i, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -129,6 +149,6 @@ public class JdbcLockProvider implements LockStorage, Lifecycle {
|
|||||||
public void close() {
|
public void close() {
|
||||||
// 删除当前节点获取的锁记录
|
// 删除当前节点获取的锁记录
|
||||||
distributedLockMapper.delete(new LambdaUpdateWrapper<DistributedLock>()
|
distributedLockMapper.delete(new LambdaUpdateWrapper<DistributedLock>()
|
||||||
.eq(DistributedLock::getLockedBy, ServerRegister.CURRENT_CID));
|
.eq(DistributedLock::getLockedBy, ServerRegister.CURRENT_CID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import com.aizuda.easy.retry.server.common.Schedule;
|
|||||||
import com.aizuda.easy.retry.server.common.config.SystemProperties;
|
import com.aizuda.easy.retry.server.common.config.SystemProperties;
|
||||||
import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
|
import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
|
||||||
import com.aizuda.easy.retry.server.common.lock.LockBuilder;
|
import com.aizuda.easy.retry.server.common.lock.LockBuilder;
|
||||||
|
import com.aizuda.easy.retry.server.common.lock.LockManager;
|
||||||
import com.aizuda.easy.retry.server.common.lock.LockProvider;
|
import com.aizuda.easy.retry.server.common.lock.LockProvider;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -52,6 +53,8 @@ public abstract class AbstractSchedule implements Schedule {
|
|||||||
} finally {
|
} finally {
|
||||||
if (lock) {
|
if (lock) {
|
||||||
lockProvider.unlock();
|
lockProvider.unlock();
|
||||||
|
} else {
|
||||||
|
LockManager.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,26 +73,16 @@ public class JobExecutorResultActor extends AbstractActor {
|
|||||||
|
|
||||||
Assert.isTrue(1 == jobTaskMapper.update(jobTask,
|
Assert.isTrue(1 == jobTaskMapper.update(jobTask,
|
||||||
new LambdaUpdateWrapper<JobTask>().eq(JobTask::getId, result.getTaskId())),
|
new LambdaUpdateWrapper<JobTask>().eq(JobTask::getId, result.getTaskId())),
|
||||||
()-> new EasyRetryServerException("更新任务实例失败"));
|
() -> new EasyRetryServerException("更新任务实例失败"));
|
||||||
|
// 先尝试完成,若已完成则不需要通过获取分布式锁来完成
|
||||||
// 存在并发问题
|
boolean tryCompleteAndStop = tryCompleteAndStop(result);
|
||||||
distributedLockHandler.lockWithDisposableAndRetry(() -> {
|
if (!tryCompleteAndStop) {
|
||||||
// 更新批次上的状态
|
// 存在并发问题
|
||||||
CompleteJobBatchDTO completeJobBatchDTO = JobTaskConverter.INSTANCE.toCompleteJobBatchDTO(result);
|
distributedLockHandler.lockWithDisposableAndRetry(() -> {
|
||||||
boolean complete = jobTaskBatchHandler.complete(completeJobBatchDTO);
|
tryCompleteAndStop(result);
|
||||||
if (complete) {
|
}, MessageFormat.format(KEY, result.getTaskBatchId(),
|
||||||
// 尝试停止任务
|
result.getJobId()), Duration.ofSeconds(3), Duration.ofSeconds(1), 6);
|
||||||
// 若是集群任务则客户端会主动关闭
|
}
|
||||||
if (result.getTaskType() != JobTaskTypeEnum.CLUSTER.getType()) {
|
|
||||||
JobTaskStopHandler instanceInterrupt = JobTaskStopFactory.getJobTaskStop(result.getTaskType());
|
|
||||||
TaskStopJobContext stopJobContext = JobTaskConverter.INSTANCE.toStopJobContext(result);
|
|
||||||
stopJobContext.setNeedUpdateTaskStatus(Boolean.FALSE);
|
|
||||||
stopJobContext.setForceStop(Boolean.TRUE);
|
|
||||||
instanceInterrupt.stop(stopJobContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, MessageFormat.format(KEY, result.getTaskBatchId(), result.getJobId()), Duration.ofSeconds(3), Duration.ofSeconds(1), 3);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -102,5 +92,24 @@ public class JobExecutorResultActor extends AbstractActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}).build();
|
}).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryCompleteAndStop(JobExecutorResultDTO result) {
|
||||||
|
CompleteJobBatchDTO completeJobBatchDTO = JobTaskConverter.INSTANCE.toCompleteJobBatchDTO(result);
|
||||||
|
boolean complete = jobTaskBatchHandler.complete(completeJobBatchDTO);
|
||||||
|
if (complete) {
|
||||||
|
// 尝试停止任务
|
||||||
|
// 若是集群任务则客户端会主动关闭
|
||||||
|
if (result.getTaskType() != JobTaskTypeEnum.CLUSTER.getType()) {
|
||||||
|
JobTaskStopHandler instanceInterrupt = JobTaskStopFactory.getJobTaskStop(result.getTaskType());
|
||||||
|
TaskStopJobContext stopJobContext = JobTaskConverter.INSTANCE.toStopJobContext(result);
|
||||||
|
stopJobContext.setNeedUpdateTaskStatus(Boolean.FALSE);
|
||||||
|
stopJobContext.setForceStop(Boolean.TRUE);
|
||||||
|
instanceInterrupt.stop(stopJobContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return complete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ public class JobTaskPrepareActor extends AbstractActor {
|
|||||||
prepare.getTaskExecutorScene());
|
prepare.getTaskExecutorScene());
|
||||||
if (TaskTypeEnum.WORKFLOW.getType().equals(jobTaskExecutorSceneEnum.getTaskType().getType())) {
|
if (TaskTypeEnum.WORKFLOW.getType().equals(jobTaskExecutorSceneEnum.getTaskType().getType())) {
|
||||||
queryWrapper.eq(JobTaskBatch::getWorkflowNodeId, prepare.getWorkflowNodeId());
|
queryWrapper.eq(JobTaskBatch::getWorkflowNodeId, prepare.getWorkflowNodeId());
|
||||||
|
queryWrapper.eq(JobTaskBatch::getWorkflowTaskBatchId, prepare.getWorkflowTaskBatchId());
|
||||||
queryWrapper.eq(JobTaskBatch::getTaskType, TaskTypeEnum.WORKFLOW.getType());
|
queryWrapper.eq(JobTaskBatch::getTaskType, TaskTypeEnum.WORKFLOW.getType());
|
||||||
} else {
|
} else {
|
||||||
queryWrapper.eq(JobTaskBatch::getTaskType, TaskTypeEnum.JOB.getType());
|
queryWrapper.eq(JobTaskBatch::getTaskType, TaskTypeEnum.JOB.getType());
|
||||||
|
@ -89,7 +89,8 @@ public class WorkflowExecutorActor extends AbstractActor {
|
|||||||
|
|
||||||
// 添加父节点,为了判断父节点的处理状态
|
// 添加父节点,为了判断父节点的处理状态
|
||||||
List<JobTaskBatch> allJobTaskBatchList = jobTaskBatchMapper.selectList(new LambdaQueryWrapper<JobTaskBatch>()
|
List<JobTaskBatch> allJobTaskBatchList = jobTaskBatchMapper.selectList(new LambdaQueryWrapper<JobTaskBatch>()
|
||||||
.select(JobTaskBatch::getWorkflowTaskBatchId, JobTaskBatch::getWorkflowNodeId, JobTaskBatch::getTaskBatchStatus)
|
.select(JobTaskBatch::getWorkflowTaskBatchId, JobTaskBatch::getWorkflowNodeId,
|
||||||
|
JobTaskBatch::getTaskBatchStatus, JobTaskBatch::getOperationReason)
|
||||||
.eq(JobTaskBatch::getWorkflowTaskBatchId, workflowTaskBatch.getId())
|
.eq(JobTaskBatch::getWorkflowTaskBatchId, workflowTaskBatch.getId())
|
||||||
.in(JobTaskBatch::getWorkflowNodeId, Sets.union(successors, Sets.newHashSet(taskExecute.getParentId())))
|
.in(JobTaskBatch::getWorkflowNodeId, Sets.union(successors, Sets.newHashSet(taskExecute.getParentId())))
|
||||||
);
|
);
|
||||||
|
@ -60,7 +60,6 @@ public abstract class AbstractWorkflowExecutor implements WorkflowExecutor, Init
|
|||||||
private TransactionTemplate transactionTemplate;
|
private TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
|
||||||
public void execute(WorkflowExecutorContext context) {
|
public void execute(WorkflowExecutorContext context) {
|
||||||
distributedLockHandler.lockWithDisposableAndRetry(
|
distributedLockHandler.lockWithDisposableAndRetry(
|
||||||
() -> {
|
() -> {
|
||||||
@ -111,7 +110,7 @@ public abstract class AbstractWorkflowExecutor implements WorkflowExecutor, Init
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, MessageFormat.format(KEY, context.getWorkflowTaskBatchId(), context.getWorkflowNodeId()),
|
}, MessageFormat.format(KEY, context.getWorkflowTaskBatchId(), context.getWorkflowNodeId()),
|
||||||
Duration.ofSeconds(5), Duration.ofSeconds(1), 3);
|
Duration.ofSeconds(6), Duration.ofSeconds(2), 12);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.aizuda.easy.retry.server.job.task.support.handler;
|
|||||||
|
|
||||||
import com.aizuda.easy.retry.common.log.EasyRetryLog;
|
import com.aizuda.easy.retry.common.log.EasyRetryLog;
|
||||||
import com.aizuda.easy.retry.server.common.lock.LockBuilder;
|
import com.aizuda.easy.retry.server.common.lock.LockBuilder;
|
||||||
|
import com.aizuda.easy.retry.server.common.lock.LockManager;
|
||||||
import com.aizuda.easy.retry.server.common.lock.LockProvider;
|
import com.aizuda.easy.retry.server.common.lock.LockProvider;
|
||||||
import com.aizuda.easy.retry.server.job.task.support.LockExecutor;
|
import com.aizuda.easy.retry.server.job.task.support.LockExecutor;
|
||||||
import com.github.rholder.retry.Attempt;
|
import com.github.rholder.retry.Attempt;
|
||||||
@ -13,9 +14,10 @@ import com.github.rholder.retry.StopStrategies;
|
|||||||
import com.github.rholder.retry.WaitStrategies;
|
import com.github.rholder.retry.WaitStrategies;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -54,10 +56,16 @@ public class DistributedLockHandler {
|
|||||||
.withRetryListener(new RetryListener() {
|
.withRetryListener(new RetryListener() {
|
||||||
@Override
|
@Override
|
||||||
public <V> void onRetry(final Attempt<V> attempt) {
|
public <V> void onRetry(final Attempt<V> attempt) {
|
||||||
if (!attempt.hasResult()) {
|
Object result = null;
|
||||||
EasyRetryLog.LOCAL.warn("第【{}】次尝试获取锁. lockName:[{}]",
|
if (attempt.hasResult()) {
|
||||||
attempt.getAttemptNumber(), lockName);
|
try {
|
||||||
|
result = attempt.get();
|
||||||
|
} catch (ExecutionException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EasyRetryLog.LOCAL.info("第【{}】次尝试获取锁. lockName:[{}] result:[{}] treadName:[{}]",
|
||||||
|
attempt.getAttemptNumber(), lockName, result, Thread.currentThread().getName());
|
||||||
}
|
}
|
||||||
}).build();
|
}).build();
|
||||||
|
|
||||||
@ -71,13 +79,20 @@ public class DistributedLockHandler {
|
|||||||
Throwable throwable = e;
|
Throwable throwable = e;
|
||||||
if (e.getClass().isAssignableFrom(RetryException.class)) {
|
if (e.getClass().isAssignableFrom(RetryException.class)) {
|
||||||
RetryException re = (RetryException) e;
|
RetryException re = (RetryException) e;
|
||||||
throwable = re.getLastFailedAttempt().getExceptionCause();
|
Attempt<?> lastFailedAttempt = re.getLastFailedAttempt();
|
||||||
|
if (lastFailedAttempt.hasException()) {
|
||||||
|
throwable = lastFailedAttempt.getExceptionCause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EasyRetryLog.LOCAL.error("lock execute error. lockName:[{}]", lockName, throwable);
|
EasyRetryLog.LOCAL.error("lock execute error. lockName:[{}]", lockName, throwable);
|
||||||
} finally {
|
} finally {
|
||||||
if (lock) {
|
if (lock) {
|
||||||
|
EasyRetryLog.LOCAL.info("[{}] 锁已释放", lockName);
|
||||||
lockProvider.unlock();
|
lockProvider.unlock();
|
||||||
|
} else {
|
||||||
|
// 未获取到锁直接清除线程中存储的锁信息
|
||||||
|
LockManager.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +105,7 @@ public class DistributedLockHandler {
|
|||||||
* @param lockName 锁名称
|
* @param lockName 锁名称
|
||||||
* @param lockAtMost 锁超时时间
|
* @param lockAtMost 锁超时时间
|
||||||
*/
|
*/
|
||||||
|
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||||
public void lockWithDisposable(String lockName, Duration lockAtMost, LockExecutor lockExecutor) {
|
public void lockWithDisposable(String lockName, Duration lockAtMost, LockExecutor lockExecutor) {
|
||||||
|
|
||||||
LockProvider lockProvider = LockBuilder.newBuilder()
|
LockProvider lockProvider = LockBuilder.newBuilder()
|
||||||
@ -107,6 +123,9 @@ public class DistributedLockHandler {
|
|||||||
} finally {
|
} finally {
|
||||||
if (lock) {
|
if (lock) {
|
||||||
lockProvider.unlock();
|
lockProvider.unlock();
|
||||||
|
} else {
|
||||||
|
// 未获取到锁直接清除线程中存储的锁信息
|
||||||
|
LockManager.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,8 +5,8 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Easy Retry</title>
|
<title>Easy Retry</title>
|
||||||
<script type="module" crossorigin src="./assets/1RK3CeRh.js"></script>
|
<script type="module" crossorigin src="./assets/06nP_ETa.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/Z7fZzXo1.css">
|
<link rel="stylesheet" crossorigin href="./assets/dSfAux_s.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -9,28 +9,28 @@
|
|||||||
<div class="log">
|
<div class="log">
|
||||||
<table class="scroller">
|
<table class="scroller">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(log, index) in logList" :key="index">
|
<tr v-for="(log, index) in logList" :key="index">
|
||||||
<td class="index">
|
<td class="index">
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="text" style="color: #2db7f5">{{ timestampToDate(log.time_stamp) }}</div>
|
<div class="text" style="color: #2db7f5">{{ timestampToDate(log.time_stamp) }}</div>
|
||||||
<div class="text" :style="{ color: LevelEnum[log.level].color }">
|
<div class="text" :style="{ color: LevelEnum[log.level].color }">
|
||||||
{{ log.level.length === 4 ? log.level + ' ' : log.level }}
|
{{ log.level.length === 4 ? log.level + ' ' : log.level }}
|
||||||
|
</div>
|
||||||
|
<div class="text" style="color: #00a3a3">[{{ log.thread }}]</div>
|
||||||
|
<div class="text" style="color: #a771bf; font-weight: 500">{{ log.location }}</div>
|
||||||
|
<div class="text">:</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text" style="color: #00a3a3">[{{ log.thread }}]</div>
|
<div class="text" style="font-size: 16px">{{ log.message }}</div>
|
||||||
<div class="text" style="color: #a771bf; font-weight: 500">{{ log.location }}</div>
|
<div class="text" style="font-size: 16px">{{ log.throwable }}</div>
|
||||||
<div class="text">:</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text" style="font-size: 16px">{{ log.message }}</div>
|
|
||||||
<div class="text" style="font-size: 16px">{{ log.throwable }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -135,6 +135,7 @@ export default {
|
|||||||
this.fromIndex = res.data.fromIndex
|
this.fromIndex = res.data.fromIndex
|
||||||
if (res.data.message) {
|
if (res.data.message) {
|
||||||
this.logList.push(...res.data.message)
|
this.logList.push(...res.data.message)
|
||||||
|
this.logList.sort((a, b) => a.time_stamp - b.time_stamp)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -153,7 +154,7 @@ export default {
|
|||||||
const hours = date.getHours()
|
const hours = date.getHours()
|
||||||
const minutes = date.getMinutes().toString().length === 1 ? '0' + date.getMinutes() : date.getMinutes().toString()
|
const minutes = date.getMinutes().toString().length === 1 ? '0' + date.getMinutes() : date.getMinutes().toString()
|
||||||
const seconds = date.getSeconds().toString().length === 1 ? '0' + date.getSeconds() : date.getSeconds().toString()
|
const seconds = date.getSeconds().toString().length === 1 ? '0' + date.getSeconds() : date.getSeconds().toString()
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${date.getMilliseconds()}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user