任务常见问题

本文介绍如何处理使用SchedulerX过程中的一些任务管理问题。

Spring应用找不到Bean怎么办?

  1. 通过应用管理连接机器查看启动方式,确保为Spring或者Spring Boot方式。
  2. JobProcessor要注入为bean,比如加@Component注解。
  3. 排查Pom依赖如果依赖spring-boot-devtools则需要排除掉。
  4. 如果JobProcessor和process方法有aop注解,需要升级到最新版本SchedulerX客户端,低版本不支持aop。
  5. 因为多加了一层代理导致Bean类型不匹配。可以放断点放入DefaultListableBeanFactory类中。其中beanDefinitionNames成员变量是Spring注册的Bean列表, 里面可以看到bean被某切面代理,例如一些用户间接引入一个错误的二方库导致该现象,排除掉即可。
1

如果以上方案无法解决问题,可以调试ThreadContainer.start方法。如果class.forName报错,class又确实存在,可能是业务方使用了某些框架,导致classLoader不一致,可以通过设置SchedulerxWorker.setClassLoader解决。

任务失败,报错“submit jobInstanceId to worker timeout”

当应用发布的时候报该问题或者偶尔报该问题时,无需处理。

如果持续报错且每次报错的workerAddr都是同一台机器,说明服务端和客户端长连接断开,需要将该Worker节点重启或者升级SchedulerX客户端版本至最新版本。升级至最新版本后,断开的长连接可自动恢复。

任务失败,报错“used space beyond 90.0%!”

磁盘已满,需要清理ECS或者容器上的磁盘空间。

任务失败,报错“ClassNotFoundException”

说明执行任务的Worker上没有该类,请确保Java任务配置的Processor类名必须是类的全路径,并非简写。

1

如果配置的jobProcessor类名正确,即为Worker上没有该类,一般为用户发错包或者该应用还连接了其他人的机器。您可以自己登录Worker机器,通过反编译查看详细情况。

1

任务失败,报错“jobInstance=xxx don't update progress more than 60s”

正在运行任务的Worker停止工作或者发布时,超过60秒没有汇报进度时,会被服务端强制终止。如果确定问题由Worker引入或者该Worker已经不存在,则无需处理。

任务执行失败,且没有错误信息

问题现象:

任务执行失败,且没有错误信息。

可能原因:

机器或业务逻辑执行失败等。

解决方案:

  • 执行列表页面,单击任务实例详情,查看子任务详情,查看对应执行失败的机器。

    如果没有子任务详情,说明为简单任务。查看基本信息的workAddr,该机器为执行任务的业务机器。

  • 登录到业务机器,打开到~/logs/schedulerx/worker.log日志。

    执行grep <实例ID> worker.log查看该实例相关的日志。如果有ERROR级别异常,查看堆栈的具体原因。

  • 错误描述为空则基本为业务逻辑执行失败且未返回失败信息,请先自行排查业务逻辑。
  • 错误描述有框架异常,请加入钉群(钉群号:23103656)联系SchedulerX技术支持人员。

如何排查任务失败的原因?

  • 如果是单机任务,业务直接抛异常,可以在执行列表页面,单击任务实例列表,在对应任务实例的操作列,单击详情查看错误信息。1
  • 如果任务没有抛异常或者使用了分布式任务,您的专业版应用可以通过日志服务来排查问题。5
  • 如果是基础版应用,您可以自行登录Worker节点,查看SchedulerX的日志和业务自己的日志进行排查。

任务运行中卡住怎么办?

问题现象:

调度任务一直处于执行中,不能结束。

可能原因:

  • 业务的问题。
  • SchedulerX的问题。

解决方案:

业务方面的问题可以按照以下方案排查,其他问题请加入钉群(钉群号:23103656)联系SchedulerX技术支持人员。

  • 专业版应用:可以通过控制台的查看堆栈功能(1.4.2及以上客户端版本可用),来排查任务异常的堆栈。1
  • 基础版应用:可以自行登录卡住的Worker节点,通过jstack命令查看堆栈,执行命令。
    jstack <pid> | grep <任务实例id> -A 20
    6

如何排查任务运行慢的原因?

开启专业版,使用链路追踪。具体操作,请参见如何接入链路追踪

任务运行实例达到上限怎么办?

问题现象:

在任务管理页面,单击运行一次,收到任务运行实例达到上限,请稍后重试提示。

可能原因:

  • 该任务已经有任务实例在运行中。
  • 运行中的任务实例达到任务配置的最大并发数。

解决方案:

如果并发数合理,无需处理。可以在任务管理页面,单击更多 > 历史记录查看运行中的任务实例

如果不合理,在目标任务的操作列,单击编辑,在高级配置里设置实例并发数

任务上一次没运行完,下一次是排队还是不运行了?

任务默认并发是1,即串行跑。如果任务执行时间比较长,上一次没运行完,下一次调度时间到了,则下一次会直接丢弃,不会运行也不会排队。

如果设置任务实例并发数为2,上一次没运行完,下一次时间到了仍然可以运行一个实例,最多同时运行两个任务实例。

如何设置一次性任务?

SchedulerX 2.0支持设置一次性任务。时间类型选择one_time即可。一次性任务不保留任务执行记录。

one_time任务运行完成后怎么查看历史记录?

one_time任务运行完会自动销毁,防止数据堆积,且不保留任何历史记录。如果需要保存历史记录,您可以开启日志服务,保留最近两周所有任务的执行日志,方便排查问题。关于如何开启日志服务,请参见应用管理

如何进行秒级别调度?

SchedulerX支持秒级别调度。cron、fix_rate不支持秒级别调度,您可以选择时间类型为second_delay,即上一次运行完之后间隔几秒再运行。

某个时间点没有调度怎么办?

某个单机任务有一个时间点没有调度运行时,您需要确认机器列表是否存在机器,并确认机器是否全部处于繁忙状态。如果不存在机器,按无可用机器或机器繁忙进行排查。更多信息,请参见无可用机器(no worker available)机器繁忙(all workers are busy)该怎么办?

建议为任务配置无可用机器报警。具体操作,请参见任务管理

SchedulerX如何设置超时时间?

SchedulerX不支持子任务级别的超时时间,只支持整个任务的超时。可以通过控制台动态修改超时时间。具体操作,请参见任务管理

为什么实例停止之后还会执行?

问题现象:

实例停止之后仍然执行。

可能原因:

任务实例停止后,SchedulerX会把Kill消息发送到客户端。客户端接收到Kill消息后,会停止下发和停止执行未执行的子任务、销毁该实例的上下文、销毁实例所有的线程池。对于已经在执行中的子任务不会被停止掉,只会中断对应的线程,所以子任务会继续运行直到结束。

解决方案:

  • 一般情况下,您无需处理,等待子任务执行结束即可。
  • 如果确实需要停止后立即结束所有运行中的任务,需要修改子任务处理逻辑,增加对当前线程Interrupt状态的处理。

如何进行任务管理高级配置?

更多信息,请参见任务管理高级配置参数说明

机器繁忙(all workers are busy)该怎么办?

可以在应用管理页面查看实例,定位繁忙状态的Worker,然后单击繁忙,即可查看超过了阈值的指标。

11

繁忙的阈值在应用管理页面通过编辑应用分组配置。

1

如果是load繁忙,您需要查看自己是否为容器(K8s)部署。如果为容器(K8s)部署,需要配置以下两个参数,否则采集的CPU使用率可能不准确。具体操作,请参见Spring Boot应用接入SchedulerX

key描述设置值起始版本
spring.schedulerx2.enableCgroupMetrics是否使用cgroup统计客户端实例的指标。容器(K8s)环境需要自己手动开启。true/false,默认false。1.2.2.2
spring.schedulerx2.cgroupPathPrefix容器内cgroup的路径。默认是/sys/fs/cgroup/cpu/,如果存在该路径则不需要设置。1.2.2.2

如何接入链路追踪?

任务调度支持全链路追踪。具体操作,请参见如何接入链路追踪

应用发布过程,任务执行卡住或变慢

问题现象:

应用发布过程,任务执行卡住或变慢。

可能原因:

对于分布式任务,处理子任务的机器下线会进行重新分发并轮询检查机器是否在线,会导致整个处理过程变慢。

解决方案:

将客户端升级至最新版本,1.7.9及以上版本该现象会得到优化。

单击运行一次后,系统提示输入实例参数,如何处理?

任务管理页面的操作列,单击运行一次,可以执行一次该调度任务。弹框中的实例参数非必填,主要用于测试。

1

单击运行一次并输入实例参数,那么代码中获取的是实例参数还是任务参数?

实例参数与任务参数是两个不同的概念,代码中具体获取的参数是由用户的业务代码决定的。

如何获取任务参数或者实例参数?

详细代码如下所示。

@Component
public class JavaDemoProcessor extends JavaProcessor {


    private static final Logger LOGGER = LoggerFactory.getLogger("schedulerxLog");


    @Override
    public ProcessResult process(JobContext jobContext) throws InterruptedException {

        LOGGER.info(JSON.toJSONString(jobContext));
        //获取任务参数
        String jobParameters = jobContext.getJobParameters();
        //获取实例参数
        String instanceParameters = jobContext.getInstanceParameters();
        LOGGER.info("任务参数:" + jobParameters);
        LOGGER.info("实例參数" + instanceParameters);
        return new ProcessResult(InstanceStatus.SUCCESS);
    }

}

如何实现填写实例参数后,代码默认获取实例参数,未填写则获取任务参数

详细代码如下所示。

@Component
public class JavaDemoProcessor extends JavaProcessor {

    private static final Logger LOGGER = LoggerFactory.getLogger("schedulerxLog");

    @Override
    public ProcessResult process(JobContext jobContext) throws InterruptedException {
        String params = null;
        if (StringUtils.isNotBlank(jobContext.getInstanceParameters())) {
            params = jobContext.getInstanceParameters();
        } else {
            params = jobContext.getJobParameters();
        }
        LOGGER.info("JavaDemoProcessor params:{}", params);
        return new ProcessResult(InstanceStatus.SUCCESS);
    }

}