报错log:
2020/11/26 17:55:08 ERROR [org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler] - Unexpected error occurred in scheduled task
org.springframework.data.redis.RedisSystemException: Redis command interrupted; nested exception is io.lettuce.core.RedisCommandInterruptedException: Command interrupted
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:62)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:270)
at org.springframework.data.redis.connection.lettuce.LettuceStreamCommands.convertLettuceAccessException(LettuceStreamCommands.java:472)
at org.springframework.data.redis.connection.lettuce.LettuceStreamCommands.xAdd(LettuceStreamCommands.java:109)
at org.springframework.data.redis.connection.DefaultedRedisConnection.xAdd(DefaultedRedisConnection.java:451)
at org.springframework.data.redis.connection.DefaultStringRedisConnection.xAdd(DefaultStringRedisConnection.java:3763)
at org.springframework.data.redis.core.DefaultStreamOperations.lambda$add$1(DefaultStreamOperations.java:135)
at org.springframework.data.redis.core.DefaultStreamOperations$$Lambda$737/411704343.doInRedis(Unknown Source)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:228)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:188)
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:96)
at org.springframework.data.redis.core.DefaultStreamOperations.add(DefaultStreamOperations.java:135)
at org.springframework.data.redis.core.StreamOperations.add(StreamOperations.java:110)
at com.SpringLearn.common.redis.JedisUtils.xadd(JedisUtils.java:740)
at com.SpringLearn.common.messageQueue.BaseMessageTrigger.send(BaseMessageTrigger.java:33)
at com.SpringLearn.service.xxxx.xxxxx.insert(PlayerActionService.java:197)
at com.SpringLearn.service.xxxxx.xxxxx$$FastClassBySpringCGLIB$$567a93ae.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$707/1475341560.proceedWithInvocation(Unknown Source)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at com.SpringLearn.service.xxxx.xxxxx$$EnhancerBySpringCGLIB$$faf84b2b.insert(<generated>)
at com.SpringLearn.service.xxxxx.xxxxxx.fold(PlayerActionService.java:178)
at com.SpringLearn.service.xxxxx.xxxxxx.fold(PlayerActionService.java:154)
at com.SpringLearn.service.xxxxx.xxxxxxxxx.sitOutGame(PlayerActionService.java:217)
at com.SpringLearn.service.xxxxxx.xxxxxxxxxx$$FastClassBySpringCGLIB$$567a93ae.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$707/1475341560.proceedWithInvocation(Unknown Source)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at com.SpringLearn.service.player.PlayerActionService$$EnhancerBySpringCGLIB$$faf84b2b.sitOutGame(<generated>)
at com.SpringLearn.service.stopWatch.excuter.PlayerActStopWatch.callBack(PlayerActStopWatch.java:43)
at com.SpringLearn.service.stopWatch.StopWatchService$StopWatchRunnable.run(StopWatchService.java:79)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: io.lettuce.core.RedisCommandInterruptedException: Command interrupted
at io.lettuce.core.protocol.AsyncCommand.await(AsyncCommand.java:87)
at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:112)
at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:69)
at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
at com.sun.proxy.$Proxy136.xadd(Unknown Source)
at org.springframework.data.redis.connection.lettuce.LettuceStreamCommands.xAdd(LettuceStreamCommands.java:106)
... 58 common frames omitted
Caused by: java.lang.InterruptedException: null
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2258)
at io.lettuce.core.protocol.AsyncCommand.await(AsyncCommand.java:83)
... 63 common frames omitted
lettuce作为redis的驱动在进行xadd命令时报错:Command interrupted(指令被中断),有时候是druid报同样的错误,两个错误相同点在下面这个图中,都是这里报了InterruptedException
CompletableFuture.get方法详情:
报错是因为Thread.interrupted()的结果是true,Thread.interrupted()方法的作用是测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。
当前线程为什么会被中断呢?苦苦思索后找到了原因:
@Slf4j
@Service
public class StopWatchService {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
/**
* 存放动态定时任务结果,用于关闭定时任务
*/
private ConcurrentHashMap<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<String, ScheduledFuture<?>>();
/**
*
* @Description:添加定时任务
* @param stopWatch
*/
public void addStopWatch(BaseStopWatchExcuter stopWatch) {
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(new StopWatchRunnable(stopWatch), stopWatch.getStartTime());
futureMap.put(stopWatch.getKey(), schedule);
}
/**
*
* @Description:取消
* @param stopWatch
* @param key
*/
public void cancel(String key) {
try {
ScheduledFuture<?> scheduledFuture = futureMap.get(key);
if(null != scheduledFuture) {
scheduledFuture.cancel(true);
futureMap.remove(key);
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
/**
* 内部类--定时任务线程
*/
private class StopWatchRunnable implements Runnable {
private BaseStopWatchExcuter stopWatch;
public StopWatchRunnable(BaseStopWatchExcuter stopWatch) {
this.stopWatch = stopWatch;
}
@Override
public void run() {
// 执行完后要取消该定时任务
this.stopWatch.callBack();
cancel(this.stopWatch.getKey());
}
}
}
这个服务是一个基于org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler,用于设定一个定时器,在指定时间点运行StopWatchRunnable线程,线程内的run方法会调用具体的StopWatchExcuter 回调方法,然后调用cancel方法。
cancel方法是为了外部逻辑能手动取消定时任务,方法中根据key从futureMap中找到ScheduledFuture,调用ScheduledFuture.cancel(boolean mayInterruptIfRunning)方法,删除map中的记录。
mayInterruptIfRunning参数为true表示不论StopWatchRunnable 线程是否运行结束都会被终止,导致Thread.interrupted()返回true的原因就在这里。
并且通过在cancel方法和callBack方法中输出日志的顺序看出,这里进行了指令重排序,将mayInterruptIfRunning参数设置为false解决了报错