# 计划任务

### 1、任务周期定义

![](/assets/task_define.png)

新建一条计划任务后，可点击任务计划修改，打开计划修改页面：

![](/assets/schedule_edit.png)

计划任务可以定义五种频率，分别是：月、周、日、时、分。

* 月：可定义每几个月的第几天（可选择多个，使用逗号隔开）执行，同时可以指定执行的具体时分。

* 周：可定义每几个周的周几执行，同时可指定执行的具体时分。

* 日：可定义每几天执行一次，同时可指定执行的具体时分。

* 时：可定义每几个小时执行一次。

* 分：可定义每几分钟执行一次。

### 2、任务维护

可在任务维护主界面进行新增、修改、删除操作。

![](/assets/task_maintain.png)

新增一条任务记录之后可以对该任务进行参数配置和权限控制：

#### 2.1 任务配置

点击任务配置，打开任务配置明细弹窗，可在此处添加、删除、修改任务所需参数。                                                                                             ![](/assets/task_parameter.png)

#### 2.2 权限控制

点击权限设置，打开权限控制明细弹窗，可在此处对任务权限人进行添加、删除、修改操作：

角色代码为权限人的代码，角色名称为权限人的名字，起始日期和结束日期控制该人员可对该任务操作的时间。                                         ![](/assets/task_authority.png)

#### 2.3 任务类的编写

想要自定义一个job，必须要继承一个抽象类AbstractJob或者AbstractJobWithIRequest，然后在`safeExecute()`方法中执行业务代码，示例代码如下：

```java
public class demoJob extends AbstractJob{
    @Autowired
    private xxxService service;//业务类
    @Override
    public void safeExecuteWithIRequest(JobExecutionContext jobExecutionContext) throws Exception {
        //map中可以获取上方定义的参数，key为参数名称，value为参数值
        JobDataMap map = jobExecutionContext.getMergedJobDataMap();
        try {
           service.dosomething();
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error(e.getMessage(), e);
            }
            exception = e;
            throw e;
        }
        if (exception != null) {
            setExecutionSummary(exception.getClass().getName() + ":" + exception.getMessage());
        } else {
            setExecutionSummary("执行完成！" );
        }     

    }
    @Override
    public boolean isRefireImmediatelyWhenException() {
        //任务发生异常时候进行的动作
        //false 挂起当前JOB等待处理
        //true 继续执行
        return false;
    }

}
```

注意：

* 调用`setExecutionSummary()`方法可以在执行记录中，记录你的业务数据的记录，或者抛出的异常的具体信息。

* 在上下文中获取JobDataMap可以拿到你在任务配置中定义的参数

### 3、计划任务工作台

#### 3.1 新建任务

1.点击左上角的新建任务按钮，可以进入以下界面创建一个新的任务：

![](/assets/job_create.png)

此处任务名称必须唯一，在lov中选择对应的任务代码。

2.下拉滚动条，可以看到如下所示的界面：

![](/assets/job_create2.png)

周期性：表示一个cron任务，可以在计划名称的lov中选定自己定义的一个周期，然后计划任务可以根据任务周期定义功能中的执行频率，以及执行的开始和结束时间，进行执行。

制定时间：选择执行的时间，然后计划任务可以根据选中的执行时间，开始执行。

立即执行：可以直接出发你定义的计划任务。

以上三种方式，在定义时只能选择一种，点击保存后，任务会自动开始进行调度。

注意：

* 在集群环境中，请确保各个节点的机器的时间一致，否则会造成job的调度出现问题。

* 在集群环境中，请不要用节点外的机器操作job。

* 在开发环境中，在config.properties中调度器自动启动的状态应该默认设置为false，在正式环境中应该设置为true（设置为true，表示调度器随着服务器启动而启动）:

在开发环境中，由于隐藏了调度的启动和关闭按钮，所以如果想打开调度器，必须要手动输入url：/job/scheduler/start，否则你的计划任务将不会执行。

#### 3.2 任务状态

1.任务执行时，状态不同，颜色也不同：

![](/assets/job_status.png)

状态说明：

* 正在执行，颜色显示为绿色。

* 发生异常，颜色显示为红色。

* 任务暂停，颜色显示为橙色。

* 任务完成，颜色显示为灰色。

* 任务阻塞，颜色显示为黑色。

2.想要修改任务的状态，或者删除任务，可以勾选对应的计划任务进行操作：

![](/assets/job_change_status.png)

备注：执行完成的任务无法恢复到执行状态。

### 4、执行记录

#### 4.1 查看任务的执行记录

![](/assets/job_infomation.png)

参数说明：

* 任务名称：计划任务名称
* 任务组：计划任务所属组别
* 任务状态：任务完成状态，正常执行完为FINISH，执行出错为FAILED，任务被禁止为VETOED
* 执行概要：任务执行过程中的信息，如执行结果，异常信息等（既setExecutionSummary方法中所设置的值）。
* 上次执行时间：上一次任务预计执行的时间点。
* 计划执行时间：预计完成上一次任务后，根据指定的执行间隔推算的本次任务执行的时间。
* 下次执行时间：预计执行完本次任务后，根据指定的执行间隔推算的下一次执行时间点。
* 实际执行时间：本次任务实际执行的时间点。

### 5、后台创建周期任务

由于在某些业务模块中，可能需要直接在后端业务代码中定义计划任务，那么这个时候，融租易中提供了创建计划任务的接口可以供直接调用。

#### 5.1 通过post请求直接创建周期任务

访问`"/hls/job/create"`地址，必须要为post请求类型，方法返回的值为jobId，请求体中的参数也必须为json格式，如下：

```
{
    "jobCreateDto": {
        "jobClassName":"default",
        "jobName": "jobname",
        "jobGroup": "DEFAULT",
        "triggerType": "CRON"
    },
    "taskId": "10001",
    "scheduleName": "schname",
    "defineStartTime": "14000000",
    "defineEndTime": "140000000",
    "businessParam": {
        "contractId": "1"
    }
}
```

json格式说明：

* jobCreateDto：该元素中，只有job是自己定义的，其他全部按照如上所示的规范填写。
* taskId：taskId表示在任务维护中，定义的任务的ID，创建的job执行的类实际上是根据任务中定义的类，所以请确保此处填写无误。
* scheduleName：scheduleName表示任务周期中定义的周期名，任务会按照scheduleName对应的周期执行。
* defineStartTime：自定义的任务开始时间，如果有需要则填写，否则直接根据周期定义中的开始时间执行，传到后台的值必须为Long类型。
* defineEndTime：自定义的任务结束时间，如果有需要则填写，否则直接根据周期定义中的时间结束，传到后台的值必须为Long类型。
* businessParam：业务所需的参数，填写后可以在任务执行时获取到。

#### 5.2 通过service中的方法创建周期任务

注入`HlsJobCreateService`，调用的方法为`createHlsJob(HlsJobDto hlsJobDto, IRequest requestCtx)`，其中HlsJobDto参数可以与上述的json相互转换，实现的效果也是一致的。