Skip to content

分布式调度操作手册

版本:V2.0.0

目标

分布式调度(ujob) 的设计目标为分布式任务调度组件,为任务调度中间件。应用通过依赖 ujob-worker 即可接入调度组件获取任务调度与分布式计算能力。

功能概述

使用简单:提供前端Web界面,允许开发者可视化地完成调度任务的管理(增、删、改、查)、任务运行状态监控和运行日志查看等功能。

定时策略完善:支持 CRON 表达式、固定频率、固定延迟和API四种定时调度策略。

执行模式丰富:支持单机、广播、Map、MapReduce 四种执行模式,其中 Map/MapReduce 处理器能使开发者寥寥数行代码便获得集群分布式计算的能力。

执行器支持广泛:支持 Spring Bean、内置/外置 Java 类,另外可以通过引入官方提供的依赖包,一键集成 Shell、Python、HTTP、SQL 等处理器,应用范围广。

运维便捷:支持在线日志功能,执行器产生的日志可以在前端控制台页面实时显示,降低 debug 成本,极大地提高开发效率。

依赖精简:最小仅依赖关系型数据库(MySQL/PostgreSQL/Oracle/MS SQLServer...)。

故障转移与恢复:任务执行失败后,可根据配置的重试策略完成重试,只要执行器集群有足够的计算节点,任务就能顺利完成。

适用场景

有定时执行需求的业务场景:如每天凌晨全量同步数据、生成业务报表、未支付订单超时取消等。

有需要全部机器一同执行的业务场景:如使用广播执行模式清理集群日志。

有需要分布式处理的业务场景:比如需要更新一大批数据,单机执行耗时非常长,可以使用Map/MapReduce 处理器完成任务的分发,调动整个集群加速计算。

有需要延迟执行某些任务的业务场景:比如订单过期处理等。

相关术语及定义

分组概念

appName:应用名称,建议与用户实际接入 ujob的应用名称保持一致,用于业务分组与隔离。一个 appName 等于一个业务集群,也就是实际的一个 Java 项目。

核心概念

任务(Job):描述了需要被 ujob调度的任务信息,包括任务名称、调度时间、处理器信息等。

任务实例( JobInstance,简称 Instance):任务(Job)被调度执行后会生成任务实例(Instance),任务实例记录了任务的运行时信息(任务与任务实例的关系类似于类与对象的关系)。

作业(Task):任务实例的执行单元,一个 JobInstance 存在至少一个 Task,具体规则如下: 单机任务(STANDALONE):一个 JobInstance 对应一个 Task 广播任务(BROADCAST):一个 JobInstance 对应 N 个 Task,N为集群机器数量,即每一台机器都会生成一个 Task Map/MapReduce任务:一个 JobInstance 对应若干个 Task,由开发者手动 map 产生

扩展概念

JVM 容器:以 Maven 工程项目的维度组织一堆 Java 文件(开发者开发的众多 Java 处理器),可以通过前端网页动态发布并被执行器加载,具有极强的扩展能力和灵活性。

OpenAPI:允许开发者通过接口来完成手工的操作,让系统整体变得更加灵活。开发者可以基于 API 便捷地扩展 UJob 原有的功能。

轻量级任务:单机执行且不需要以固定频率或者固定延迟执行的任务

重量级任务:非单机执行或者以固定频率/延迟执行的任务

定时任务类型

API -> 不需要填写任何参数,表明该任务由 OpenAPI 触发

CRON -> 填写 CRON 表达式

固定频率 -> 填写整数,单位毫秒

固定延迟 -> 填写整数,单位毫秒

接入配置

pom.xml 配置

xml
<dependency>
  <groupId>com.cpit.ujob</groupId>
  <artifactId>ujob-worker-spring-boot-starter</artifactId>
  <version>2.1.0</version>
</dependency>

application.yml 配置

properties
ujob:
  worker:
    enabled: true
    # 工作端口,可选,默认 27777
    port: 27777
    # 接入应用名称,用于分组隔离,推荐填写 本 Java 项目名称
    app-name: app1
    # 调度服务器地址,IP:Port 或 域名,多值逗号分隔
    server-address: 127.0.0.1:7700
    # 协议
    protocol: http
    # 持久化方式
    store-strategy: disk
    # 任务返回结果信息的最大长度,超过这个长度的信息会被截断
    max-result-length: 4096
    # 单个任务追加的工作流上下文最大长度,超过这个长度的会被直接丢弃
    max-appended-wf-context-length: 4096
    docker-deploy: false

注册

应用注册

进入分布式调度登录页面(推荐使用谷歌浏览器)

img

点击“执行注册应用”进行应用注册。

img

注册的应用名称要与application.yml 中的 ujob.worker.app-name名称保持一致。

报警用户录入

点击“报警用户录入”进行报警用户注册。

img

填写报警用户信息,点击“注册”。

登录

img

在登录页面,输入应用名称、密码,点击“登录”按钮进入系统工作台主界面。

工作台

img

顶部统计任务总数、当前运行实例数、近期失败任务数及集群机器数。

表格中是连接到调度服务器的执行器信息。

右侧现在应用名称、文档地址、调度服务器时间及本地时间等信息。调度服务器时间与本地时间不一致可能导致调度错误。

任务管理

任务列表

点击左侧菜单“任务管理”,打开任务管理页面。

img

创建任务

点击“新增任务”按钮,打开新增任务弹窗,填写任务信息,点“保存”。

img

编辑任务

点击“任务列表-编辑”按钮,打开编辑任务弹窗,填写任务信息,点“保存”。

img

任务信息字段说明

任务名称:任务名称

任务描述:任务描述

任务参数:任务处理时能够获取到的参数

定时信息:该任务的触发方式(API、CRON、固定频率、固定延迟)

API -> 不需要填写任何参数,表明该任务由 OpenAPI 触发

CRON -> 填写 CRON 表达式

固定频率 -> 填写整数,单位毫秒

固定延迟 -> 填写整数,单位毫秒

生命周期:定时策略生效的时间段

执行配置:任务执行器核心配置(执行类型、处理器类型、类名路径)

运行配置:包括最大实例数、单机线程并发数、运行时间限制

重试配置:包括Instance 重试次数、Task 重试次数

机器配置:包括最低 CPU 核心数、最低内存(GB)、最低磁盘(GB)

集群配置:包括执行机器地址、最大执行机器数量

报警配置:包括报警通知人员、错误阈值、统计窗口、沉默窗口

单机处理器示例

简单示例

java
package com.cpit.ujob.samples.processors;

import com.cpit.ujob.worker.core.processor.ProcessResult;
import com.cpit.ujob.worker.core.processor.TaskContext;
import com.cpit.ujob.worker.core.processor.sdk.BasicProcessor;
import com.cpit.ujob.worker.log.OmsLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Slf4j
@Component
public class SimpleProcessor implements BasicProcessor {


    @Override
    public ProcessResult process(TaskContext context) throws Exception {

        OmsLogger logger = context.getOmsLogger();
        String jobParams = Optional.ofNullable(context.getJobParams()).orElse("S");
        logger.info("Current context:{}", context.getWorkflowContext());
        logger.info("Current job params:{}", jobParams);
        return jobParams.contains("F") ? new ProcessResult(false) : new ProcessResult(true, "yeah!");

    }
}

执行配置:执行类型选择单机处理器,处理器类型选择内建,类名路径填写com.cpit.ujob.samples.processors.SimpleProcessor

延时示例

java
package com.cpit.ujob.samples.processors;

import lombok.extern.slf4j.Slf4j;
import com.cpit.ujob.worker.core.processor.ProcessResult;
import com.cpit.ujob.worker.core.processor.TaskContext;
import com.cpit.ujob.worker.core.processor.sdk.BasicProcessor;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class TimeoutProcessor implements BasicProcessor {
    @Override
    public ProcessResult process(TaskContext context) throws Exception {
        long sleepTime = Long.parseLong(context.getJobParams());
        log.info("TaskInstance({}) will sleep {} ms", context.getInstanceId(), sleepTime);
        Thread.sleep(Long.parseLong(context.getJobParams()));
        return new ProcessResult(true, "impossible~~~~QAQ~");
    }
}

执行配置:执行类型选择单机处理器,处理器类型选择内建,类名路径填写com.cpit.ujob.samples.processors.TimeoutProcessor

注意:任务参数填写毫秒数。

广播处理器示例

java
package com.cpit.ujob.samples.processors;

import com.cpit.ujob.common.utils.NetUtils;
import com.cpit.ujob.worker.core.processor.ProcessResult;
import com.cpit.ujob.worker.core.processor.TaskContext;
import com.cpit.ujob.worker.core.processor.TaskResult;
import com.cpit.ujob.worker.core.processor.sdk.BroadcastProcessor;
import com.cpit.ujob.worker.log.OmsLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component
public class BroadcastProcessorDemo implements BroadcastProcessor {

    @Override
    public ProcessResult preProcess(TaskContext context) {
        System.out.println("===== BroadcastProcessorDemo#preProcess ======");
        context.getOmsLogger().info("BroadcastProcessorDemo#preProcess, current host: {}", NetUtils.getLocalHost());
        if ("rootFailed".equals(context.getJobParams())) {
            return new ProcessResult(false, "console need failed");
        } else {
            return new ProcessResult(true);
        }
    }

    @Override
    public ProcessResult process(TaskContext taskContext) throws Exception {
        OmsLogger logger = taskContext.getOmsLogger();
        System.out.println("===== BroadcastProcessorDemo#process ======");
        logger.info("BroadcastProcessorDemo#process, current host: {}", NetUtils.getLocalHost());
        long sleepTime = 1000;
        try {
            sleepTime = Long.parseLong(taskContext.getJobParams());
        } catch (Exception e) {
            logger.warn("[BroadcastProcessor] parse sleep time failed!", e);
        }
        Thread.sleep(Math.max(sleepTime, 1000));
        return new ProcessResult(true);
    }

    @Override
    public ProcessResult postProcess(TaskContext context, List<TaskResult> taskResults) {
        System.out.println("===== BroadcastProcessorDemo#postProcess ======");
        context.getOmsLogger().info("BroadcastProcessorDemo#postProcess, current host: {}, taskResult: {}", NetUtils.getLocalHost(), taskResults);
        return new ProcessResult(true, "success");
    }
}

执行配置:执行类型选择单机处理器,处理器类型选择内建,类名路径填写com.cpit.ujob.samples.processors.BroadcastProcessorDemo

Map处理器示例

java
package com.cpit.ujob.samples.processors;

import com.cpit.ujob.common.serialize.JsonUtils;
import com.cpit.ujob.samples.MysteryService;
import com.cpit.ujob.worker.core.processor.ProcessResult;
import com.cpit.ujob.worker.core.processor.TaskContext;
import com.cpit.ujob.worker.core.processor.sdk.MapProcessor;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

@Component
public class MapProcessorDemo implements MapProcessor {

    @Resource
    private MysteryService mysteryService;

    /**
     * 每一批发送任务大小
     */
    private static final int BATCH_SIZE = 100;
    /**
     * 发送的批次
     */
    private static final int BATCH_NUM = 5;

    @Override
    public ProcessResult process(TaskContext context) throws Exception {

        log.info("============== MapProcessorDemo#process ==============");
        log.info("isRootTask:{}", isRootTask());
        log.info("taskContext:{}", JsonUtils.toJSONString(context));
        log.info("{}", mysteryService.hasaki());

        if (isRootTask()) {
            log.info("==== MAP ====");
            List<SubTask> subTasks = Lists.newLinkedList();
            for (int j = 0; j < BATCH_NUM; j++) {
                SubTask subTask = new SubTask();
                subTask.siteId = j;
                subTask.itemIds = Lists.newLinkedList();
                subTasks.add(subTask);
                for (int i = 0; i < BATCH_SIZE; i++) {
                    subTask.itemIds.add(i + j * 100);
                }
            }
            map(subTasks, "MAP_TEST_TASK");
            return new ProcessResult(true, "map successfully");
        } else {

            log.info("==== PROCESS ====");
            SubTask subTask = (SubTask) context.getSubTask();
            for (Integer itemId : subTask.getItemIds()) {
                if (Thread.interrupted()) {
                    // 任务被中断
                    log.info("job has been stop! so stop to process subTask: {} => {}", subTask.getSiteId(), itemId);
                    break;
                }
                log.info("processing subTask: {} => {}", subTask.getSiteId(), itemId);
                int max = Integer.MAX_VALUE >> 7;
                for (int i = 0; ; i++) {
                    // 模拟耗时操作
                    if (i > max) {
                        break;
                    }
                }
            }
            // 测试在 Map 任务中追加上下文
            context.getWorkflowContext().appendData2WfContext("Yasuo", "A sword's poor company for a long road.");
            boolean b = ThreadLocalRandom.current().nextBoolean();
            if (context.getCurrentRetryTimes() >= 1) {
                // 重试的话一定会成功
                b = true;
            }
            return new ProcessResult(b, "RESULT:" + b);
        }
    }

    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class SubTask {
        private Integer siteId;
        private List<Integer> itemIds;
    }
}

执行配置:执行类型选择单机处理器,处理器类型选择内建,类名路径填写com.cpit.ujob.samples.processors.MapProcessorDemo

MapReduce处理器示例

java
package com.cpit.ujob.samples.processors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cpit.ujob.common.serialize.JsonUtils;
import com.cpit.ujob.worker.core.processor.ProcessResult;
import com.cpit.ujob.worker.core.processor.TaskContext;
import com.cpit.ujob.worker.core.processor.TaskResult;
import com.cpit.ujob.worker.core.processor.sdk.MapReduceProcessor;
import com.cpit.ujob.worker.log.OmsLogger;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

@Slf4j
@Component
public class MapReduceProcessorDemo implements MapReduceProcessor {

    @Override
    public ProcessResult process(TaskContext context) throws Exception {

        OmsLogger omsLogger = context.getOmsLogger();

        log.info("============== TestMapReduceProcessor#process ==============");
        log.info("isRootTask:{}", isRootTask());
        log.info("taskContext:{}", JsonUtils.toJSONString(context));

        // 根据控制台参数获取MR批次及子任务大小
        final JSONObject jobParams = JSONObject.parseObject(context.getJobParams());

        Integer batchSize = (Integer) jobParams.getOrDefault("batchSize", 100);
        Integer batchNum = (Integer) jobParams.getOrDefault("batchNum", 10);

        if (isRootTask()) {
            log.info("==== MAP ====");
            omsLogger.info("[DemoMRProcessor] start root task~");
            List<TestSubTask> subTasks = Lists.newLinkedList();
            for (int j = 0; j < batchNum; j++) {
                for (int i = 0; i < batchSize; i++) {
                    int x = j * batchSize + i;
                    subTasks.add(new TestSubTask("name" + x, x));
                }
                map(subTasks, "MAP_TEST_TASK");
                subTasks.clear();
            }
            omsLogger.info("[DemoMRProcessor] map success~");
            return new ProcessResult(true, "MAP_SUCCESS");
        } else {
            log.info("==== NORMAL_PROCESS ====");
            omsLogger.info("[DemoMRProcessor] process subTask: {}.", JSON.toJSONString(context.getSubTask()));
            log.info("subTask: {}", JsonUtils.toJSONString(context.getSubTask()));
            Thread.sleep(1000);
            if (context.getCurrentRetryTimes() == 0) {
                return new ProcessResult(false, "FIRST_FAILED");
            } else {
                return new ProcessResult(true, "PROCESS_SUCCESS");
            }
        }
    }

    @Override
    public ProcessResult reduce(TaskContext context, List<TaskResult> taskResults) {
        log.info("================ MapReduceProcessorDemo#reduce ================");
        log.info("TaskContext: {}", JSONObject.toJSONString(context));
        log.info("List<TaskResult>: {}", JSONObject.toJSONString(taskResults));
        context.getOmsLogger().info("MapReduce job finished, result is {}.", taskResults);

        boolean success = ThreadLocalRandom.current().nextBoolean();
        return new ProcessResult(success, context + ": " + success);
    }

    @Getter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public static class TestSubTask {
        private String name;
        private int age;
    }
}

执行配置:执行类型选择单机处理器,处理器类型选择内建,类名路径填写com.cpit.ujob.samples.processors.MapProcessorDemo

OpenApi

定时信息-时间表达式选择API类型

java
package com.cpit.ujob.samples.controller;

import com.cpit.ujob.client.UJobClient;
import com.cpit.ujob.common.enums.DispatchStrategy;
import com.cpit.ujob.common.enums.ExecuteType;
import com.cpit.ujob.common.enums.ProcessorType;
import com.cpit.ujob.common.enums.TimeExpressionType;
import com.cpit.ujob.common.model.AlarmConfig;
import com.cpit.ujob.common.model.LogConfig;
import com.cpit.ujob.common.request.http.SaveJobInfoRequest;
import com.cpit.ujob.common.response.InstanceInfoDTO;
import com.cpit.ujob.common.response.JobInfoDTO;
import com.cpit.ujob.common.response.ResultDTO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/demo")
public class DemoController {
    //  根据jobId查询任务详情
    @GetMapping(value = "/detailJob")
    public ResultDTO jobdetails(){
    // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  参数任务id
        ResultDTO<JobInfoDTO> jobInfoDTOResultDTO = client.fetchJob(351L);
        return  jobInfoDTOResultDTO;

    }


    //  创建/修改任务
    @GetMapping(value = "/editJob")
    public void editJob(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        SaveJobInfoRequest request =new SaveJobInfoRequest();
        AlarmConfig config = new AlarmConfig();
        config.setAlertThreshold(0);
        config.setSilenceWindowLen(0);
        config.setStatisticWindowLen(0);
        request.setAlarmConfig(config);
        request.setAppId(347L);
        request.setDesignatedWorkers("");
        request.setConcurrency(5);
        request.setDispatchStrategy(DispatchStrategy.HEALTH_FIRST);
        request.setEnable(false);
        request.setExecuteType(ExecuteType.STANDALONE);
        request.setExtra(null);
        request.setInstanceRetryNum(0);
        request.setInstanceTimeLimit(0L);
        request.setJobDescription("修改定时任务修改定时任务修改定时任务修改定时任务");
        request.setJobName("修改定时任务");
        request.setJobParams("10000");
        request.setLifeCycle(null);
        LogConfig logconfig = new LogConfig();
        logconfig.setType(null);
        logconfig.setLevel(null);
        logconfig.setLoggerName(null);
        request.setLogConfig(logconfig);
        request.setMaxInstanceNum(0);
        request.setMaxWorkerCount(0);
        request.setMinCpuCores(0);
        request.setMinDiskSpace(0);
        request.setMinCpuCores(0);
        request.setProcessorInfo("com.cpit.ujob.samples.processors.TimeoutProcessor");
        request.setProcessorType(ProcessorType.BUILT_IN);
        request.setTag(null);
        request.setTaskRetryNum(1);
        request.setTimeExpression("3/20 * * * * ? ");
        request.setTimeExpressionType(TimeExpressionType.CRON);
        request.setId(355L);
        client.saveJob(request);
    }
    @GetMapping(value = "/addJob")
    public void addJob(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        SaveJobInfoRequest request =new SaveJobInfoRequest();
        AlarmConfig config = new AlarmConfig();
        config.setAlertThreshold(0);
        config.setSilenceWindowLen(0);
        config.setStatisticWindowLen(0);
        request.setAlarmConfig(config);
        request.setAppId(347L);
        request.setDesignatedWorkers("");
        request.setConcurrency(5);
        request.setDispatchStrategy(DispatchStrategy.HEALTH_FIRST);
        request.setEnable(false);
        request.setExecuteType(ExecuteType.STANDALONE);
        request.setExtra(null);
        request.setInstanceRetryNum(0);
        request.setInstanceTimeLimit(0L);
        request.setJobDescription("新增定时任务新增定时任务新增定时任务新增定时任务");
        request.setJobName("新增定时任务");
        request.setJobParams("10000");
        request.setLifeCycle(null);
        LogConfig logconfig = new LogConfig();
        logconfig.setType(null);
        logconfig.setLevel(null);
        logconfig.setLoggerName(null);
        request.setLogConfig(logconfig);
        request.setMaxInstanceNum(0);
        request.setMaxWorkerCount(0);
        request.setMinCpuCores(0);
        request.setMinDiskSpace(0);
        request.setMinCpuCores(0);
        request.setProcessorInfo("com.cpit.ujob.samples.processors.TimeoutProcessor");
        request.setProcessorType(ProcessorType.BUILT_IN);
        request.setTag(null);
        request.setTaskRetryNum(1);
        request.setTimeExpression("3/20 * * * * ? ");
        request.setTimeExpressionType(TimeExpressionType.CRON);
        client.saveJob(request);
    }

    //    启用任务  参数任务id
    @GetMapping(value = "/enableJob")
    public void enableJob(){
    // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
         //  参数任务id
        client.enableJob(351L);
    }

    //    禁用任务
    @GetMapping(value = "/disableJob")
    public void disableJob(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  参数任务id
        client.disableJob(351L);
    }
    //    删除任务
    @GetMapping(value = "/deleteJob")
    public void deleteJob(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  参数任务id
        client.deleteJob(351L);
    }
    //    运行任务
    @GetMapping(value = "/runJob")
    public void runJob(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  参数任务id  任务参数  延迟时间
        client.runJob(351L,"{code:0}",1000);
    }

    //    取消某个定时任务实例
    @GetMapping(value = "/cancelInstance")
    public void cancelInstance(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  任务实例id  
        client.cancelInstance(690855948855552704L);
    }

    //    停止某个任务实例
    @GetMapping(value = "/stopInstance")
    public void stopInstance(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  任务实例id  
        client.stopInstance(690855948855552704L);
    }


    //    查询某个任务实例
    @GetMapping(value = "/fetchInstanceInfo")
    public ResultDTO fetchInstanceInfo(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  任务实例id  
        ResultDTO<InstanceInfoDTO> instanceInfoDTOResultDTO = client.fetchInstanceInfo(690855948855552704L);
        return instanceInfoDTOResultDTO;
    }

    //    查询某个任务实例的状态
    @GetMapping(value = "/fetchInstanceStatus")
    public ResultDTO fetchInstanceStatus(){
        // 初始化 client,需要server地址和应用名称作为参数
        UJobClient client = new UJobClient("127.0.0.1:7700", "app1", "123456");
        //  任务实例id  
        return client.fetchInstanceStatus(690916403582085824L);
    }
}

运行任务

点击任务列表中“运行”按钮,立即运行本任务。

img

运行状态

任务被关闭后不再被调度。

img

参数运行

点击任务列表中”更多-运行参数”按钮,填写参数运行,点击“保存”。

img

在“任务实例列表-详情”中可以查看任务实例参数。

运行记录

点击任务列表中”更多-运行记录”按钮,跳转到任务实例列表中查看当前的任务实例信息。

复制

点击任务列表中”更多-复制”按钮,复制当前任务。

删除

点击任务列表中”更多-删除”按钮,删除当前任务。

任务实例

任务实例列表

点击左侧菜单“任务实例”,打开任务实例页面。

img

详情

点击任务实例列表中“详情”按钮,查看当前任务详细运行信息。

imgimg

日志

点击任务实例列表中“日志”按钮,查看当前任务实例日志。

重试

点击任务实例列表中“重试”按钮,对任务实例进行重试。

停止

点击任务实例列表中“停止”按钮,对正在运行的任务实例进行停止。