Administrator
发布于 2024-08-07 / 18 阅读
0
0

Springboot定时任务卡死问题

springboot框架使用@Scheduled注解实现的单线程定时任务卡死,原因一般是没有设置超时策略导致无限期等待。

定位问题代码

  1. 使用jstack获取应用线程快照

    # 1.服务器上找一下文件在哪
    [root@iZ2ze616zb6x1rqtgc7w9qZ ~]# which java
    /home/jdk8/jdk1.8.0_271/bin/java
    [root@iZ2ze616zb6x1rqtgc7w9qZ ~]# cd /home/jdk8/jdk1.8.0_271/bin/
    [root@iZ2ze616zb6x1rqtgc7w9qZ bin]# ls |grep jstack
    jstack
    
    # 2.查看应用的进程ID:23417
    [root@iZ2ze616zb6x1rqtgc7w9qZ bin]# ps -ef|grep ruoyi
    root     20580 20029  0 16:02 pts/0    00:00:00 grep --color=auto ruoyi
    root     23417     1  0 Jul19 ?        00:42:48 java -Xms128m -Xmx512m -jar ruoyi-admin.jar
    
    # 3.生成线程快照
    [root@iZ2ze616zb6x1rqtgc7w9qZ bin]# jstack -l 23417 > /home/ruoyi-dump.txt
  2. 查看ruoyi-dump.txt文件中定时任务线程状态和发生问题的代码位置

    "pool-2-thread-16" #66 prio=5 os_prio=0 tid=0x00007f92a0003000 nid=0x541b waiting on condition [0x00007f9265743000]
       java.lang.Thread.State: TIMED_WAITING (sleeping)
    	at java.lang.Thread.sleep(Native Method)
    	at com.suwell.ofd.custom.agent.HTTPAgent.convert(HTTPAgent.java:167)
    	at com.suwell.ofd.custom.agent.ConvertAgent.convert(ConvertAgent.java:494)
    	at com.jiangk.apilicense.service.CreateOfdService.makeOFD(CreateOfdService.java:595)
    	at com.jiangk.apilicense.service.CreateOfdService$$FastClassBySpringCGLIB$$9bc09320.invoke(<generated>)
    	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
  3. 根据第二步可以定位定时任务卡死在CreateOfdService.java:595行

    ...
    Packet packet = new Packet(PackType.COMMON, Target.OFD);
    packet.file(new Common(null, "ofd", new FileInputStream(srcfile_final)));
    packet.seal("Suwell_WebOES", null,seal);
    # 这个方法是调用外部服务生成OFD文件,一直没有相应导致定时任务卡死。
    haseal.convert(packet,new FileOutputStream(ofdoutpath_final));
    ...

解决办法

  • 调用外部请求增加超时处理,示例

    			// 为外部请求创建一个单线程
    	    	ExecutorService executor = Executors.newSingleThreadExecutor();
    	        Callable<String> call = new Callable<String>() {
    	            @Override
    	            public String call() throws Exception {
    	                //开始执行耗时操作
    	            	haseal.convert(packet, new FileOutputStream(ofdoutpath_final));
    	                return "证照转换方法“haseal.convert”执行执行完成!";
    	            }
    	        };
    	        try {
    	            Future<String> future = executor.submit(call);
    	            future.get(1000 * 10, TimeUnit.MILLISECONDS); //任务处理超时时间设为 10 秒
    	        } catch (TimeoutException ex) {
    	            System.out.println("OFD转换服务处理超时....");
    	            throw new ResourceNotFoundException(gridDataDTO.getIdcard() + " OFD转换服务调用超时!");
    	        }finally {
    	            // 关闭线程池
    	            executor.shutdown();
                }


评论