Browse Source

[Feature][api] schedule add timezone support #5259 (#5465)

* [Feature][api] schedule add timezone support #5259

* import moment-timezone

* fix code smell
pull/3/MERGE
ruanwenjun 3 years ago committed by GitHub
parent
commit
a925f64571
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/SchedulerController.java
  2. 112
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/ScheduleParam.java
  3. 17
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java
  4. 30
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java
  5. 13
      dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java
  6. 567
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/Schedule.java
  7. 4
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ScheduleMapper.xml
  8. 1
      dolphinscheduler-dist/release-docs/LICENSE
  9. 20
      dolphinscheduler-dist/release-docs/licenses/ui-licenses/LICENSE-moment-timezone
  10. 45
      dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/QuartzExecutors.java
  11. 1
      dolphinscheduler-ui/package.json
  12. 22
      dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/timing.vue
  13. 1
      dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
  14. 1
      dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
  15. 1
      sql/dolphinscheduler_mysql.sql
  16. 1
      sql/dolphinscheduler_postgre.sql
  17. 20
      sql/upgrade/1.4.0_schema/mysql/dolphinscheduler_ddl.sql
  18. 17
      sql/upgrade/1.4.0_schema/postgresql/dolphinscheduler_ddl.sql

3
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/SchedulerController.java

@ -94,7 +94,8 @@ public class SchedulerController extends BaseController {
@ApiOperation(value = "createSchedule", notes = "CREATE_SCHEDULE_NOTES")
@ApiImplicitParams({
@ApiImplicitParam(name = "processDefinitionId", value = "PROCESS_DEFINITION_ID", required = true, dataType = "Int", example = "100"),
@ApiImplicitParam(name = "schedule", value = "SCHEDULE", dataType = "String", example = "{'startTime':'2019-06-10 00:00:00','endTime':'2019-06-13 00:00:00','crontab':'0 0 3/6 * * ? *'}"),
@ApiImplicitParam(name = "schedule", value = "SCHEDULE", dataType = "String",
example = "{'startTime':'2019-06-10 00:00:00','endTime':'2019-06-13 00:00:00','timezoneId':'America/Phoenix','crontab':'0 0 3/6 * * ? *'}"),
@ApiImplicitParam(name = "warningType", value = "WARNING_TYPE", type = "WarningType"),
@ApiImplicitParam(name = "warningGroupId", value = "WARNING_GROUP_ID", dataType = "Int", example = "100"),
@ApiImplicitParam(name = "failureStrategy", value = "FAILURE_STRATEGY", type = "FailureStrategy"),

112
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/ScheduleParam.java

@ -14,62 +14,74 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dolphinscheduler.api.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
package org.apache.dolphinscheduler.api.dto;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* schedule parameters
*/
public class ScheduleParam {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date startTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date endTime;
private String crontab;
public ScheduleParam() {
}
public ScheduleParam(Date startTime, Date endTime, String crontab) {
this.startTime = startTime;
this.endTime = endTime;
this.crontab = crontab;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getCrontab() {
return crontab;
}
public void setCrontab(String crontab) {
this.crontab = crontab;
}
@Override
public String toString() {
return "ScheduleParam{" +
"startTime=" + startTime +
", endTime=" + endTime +
", crontab='" + crontab + '\'' +
'}';
}
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date endTime;
private String crontab;
private String timezoneId;
public ScheduleParam() {
}
public ScheduleParam(Date startTime, Date endTime, String timezoneId, String crontab) {
this.startTime = startTime;
this.endTime = endTime;
this.timezoneId = timezoneId;
this.crontab = crontab;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getCrontab() {
return crontab;
}
public void setCrontab(String crontab) {
this.crontab = crontab;
}
public String getTimezoneId() {
return timezoneId;
}
public void setTimezoneId(String timezoneId) {
this.timezoneId = timezoneId;
}
@Override
public String toString() {
return "ScheduleParam{"
+ "startTime=" + startTime
+ ", endTime=" + endTime
+ ", crontab='" + crontab + '\''
+ ", timezoneId='" + timezoneId + '\''
+ '}';
}
}

17
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java

@ -157,6 +157,7 @@ public class SchedulerServiceImpl extends BaseServiceImpl implements SchedulerSe
return result;
}
scheduleObj.setCrontab(scheduleParam.getCrontab());
scheduleObj.setTimezoneId(scheduleParam.getTimezoneId());
scheduleObj.setWarningType(warningType);
scheduleObj.setWarningGroupId(warningGroupId);
scheduleObj.setFailureStrategy(failureStrategy);
@ -258,6 +259,7 @@ public class SchedulerServiceImpl extends BaseServiceImpl implements SchedulerSe
return result;
}
schedule.setCrontab(scheduleParam.getCrontab());
schedule.setTimezoneId(scheduleParam.getTimezoneId());
}
if (warningType != null) {
@ -471,20 +473,9 @@ public class SchedulerServiceImpl extends BaseServiceImpl implements SchedulerSe
}
public void setSchedule(int projectId, Schedule schedule) {
int scheduleId = schedule.getId();
logger.info("set schedule, project id: {}, scheduleId: {}", projectId, scheduleId);
Date startDate = schedule.getStartTime();
Date endDate = schedule.getEndTime();
String jobName = QuartzExecutors.buildJobName(scheduleId);
String jobGroupName = QuartzExecutors.buildJobGroupName(projectId);
Map<String, Object> dataMap = QuartzExecutors.buildDataMap(projectId, scheduleId, schedule);
QuartzExecutors.getInstance().addJob(ProcessScheduleJob.class, jobName, jobGroupName, startDate, endDate,
schedule.getCrontab(), dataMap);
logger.info("set schedule, project id: {}, scheduleId: {}", projectId, schedule.getId());
QuartzExecutors.getInstance().addJob(ProcessScheduleJob.class, projectId, schedule);
}
/**

30
dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java

@ -22,9 +22,11 @@ import org.apache.dolphinscheduler.common.Constants;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -492,6 +494,34 @@ public class DateUtils {
return getCurrentTime(Constants.YYYYMMDDHHMMSSSSS);
}
/**
* transform date to target timezone date
* <p>e.g.
* <p> if input date is 2020-01-01 00:00:00 current timezone is CST
* <p>targetTimezoneId is MST
* <p>this method will return 2020-01-01 15:00:00
*/
public static Date getTimezoneDate(Date date, String targetTimezoneId) {
if (StringUtils.isEmpty(targetTimezoneId)) {
return date;
}
String dateToString = dateToString(date);
LocalDateTime localDateTime = LocalDateTime.parse(dateToString, DateTimeFormatter.ofPattern(Constants.YYYY_MM_DD_HH_MM_SS));
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, TimeZone.getTimeZone(targetTimezoneId).toZoneId());
return Date.from(zonedDateTime.toInstant());
}
/**
* get timezone by timezoneId
*/
public static TimeZone getTimezone(String timezoneId) {
if (StringUtils.isEmpty(timezoneId)) {
return null;
}
return TimeZone.getTimeZone(timezoneId);
}
static final long C0 = 1L;
static final long C1 = C0 * 1000L;
static final long C2 = C1 * 1000L;

13
dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java

@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.common.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import org.junit.Assert;
import org.junit.Test;
@ -204,4 +205,16 @@ public class DateUtilsTest {
Assert.assertNull(DateUtils.format2Duration(d1, d2));
}
@Test
public void testTransformToTimezone() {
Date date = new Date();
Date mst = DateUtils.getTimezoneDate(date, TimeZone.getDefault().getID());
Assert.assertEquals(DateUtils.dateToString(date), DateUtils.dateToString(mst));
}
@Test
public void testGetTimezone() {
Assert.assertNull(DateUtils.getTimezone(null));
Assert.assertEquals(TimeZone.getTimeZone("MST"), DateUtils.getTimezone("MST"));
}
}

567
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/Schedule.java

@ -14,13 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dolphinscheduler.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.dolphinscheduler.common.enums.FailureStrategy;
import org.apache.dolphinscheduler.common.enums.Priority;
import org.apache.dolphinscheduler.common.enums.ReleaseState;
@ -28,6 +24,12 @@ import org.apache.dolphinscheduler.common.enums.WarningType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* schedule
*
@ -35,278 +37,285 @@ import java.util.Date;
@TableName("t_ds_schedules")
public class Schedule {
@TableId(value="id", type=IdType.AUTO)
private int id;
/**
* process definition id
*/
private int processDefinitionId;
/**
* process definition name
*/
@TableField(exist = false)
private String processDefinitionName;
/**
* project name
*/
@TableField(exist = false)
private String projectName;
/**
* schedule description
*/
@TableField(exist = false)
private String definitionDescription;
/**
* schedule start time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date startTime;
/**
* schedule end time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date endTime;
/**
* crontab expression
*/
private String crontab;
/**
* failure strategy
*/
private FailureStrategy failureStrategy;
/**
* warning type
*/
private WarningType warningType;
/**
* create time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createTime;
/**
* update time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date updateTime;
/**
* created user id
*/
private int userId;
/**
* created user name
*/
@TableField(exist = false)
private String userName;
/**
* release state
*/
private ReleaseState releaseState;
/**
* warning group id
*/
private int warningGroupId;
/**
* process instance priority
*/
private Priority processInstancePriority;
/**
* worker group
*/
private String workerGroup;
public int getWarningGroupId() {
return warningGroupId;
}
public void setWarningGroupId(int warningGroupId) {
this.warningGroupId = warningGroupId;
}
public Schedule() {
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getCrontab() {
return crontab;
}
public void setCrontab(String crontab) {
this.crontab = crontab;
}
public FailureStrategy getFailureStrategy() {
return failureStrategy;
}
public void setFailureStrategy(FailureStrategy failureStrategy) {
this.failureStrategy = failureStrategy;
}
public WarningType getWarningType() {
return warningType;
}
public void setWarningType(WarningType warningType) {
this.warningType = warningType;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public ReleaseState getReleaseState() {
return releaseState;
}
public void setReleaseState(ReleaseState releaseState) {
this.releaseState = releaseState;
}
public int getProcessDefinitionId() {
return processDefinitionId;
}
public void setProcessDefinitionId(int processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
public String getProcessDefinitionName() {
return processDefinitionName;
}
public void setProcessDefinitionName(String processDefinitionName) {
this.processDefinitionName = processDefinitionName;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Priority getProcessInstancePriority() {
return processInstancePriority;
}
public void setProcessInstancePriority(Priority processInstancePriority) {
this.processInstancePriority = processInstancePriority;
}
public String getWorkerGroup() {
return workerGroup;
}
public void setWorkerGroup(String workerGroup) {
this.workerGroup = workerGroup;
}
@Override
public String toString() {
return "Schedule{" +
"id=" + id +
", processDefinitionId=" + processDefinitionId +
", processDefinitionName='" + processDefinitionName + '\'' +
", projectName='" + projectName + '\'' +
", description='" + definitionDescription + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
", crontab='" + crontab + '\'' +
", failureStrategy=" + failureStrategy +
", warningType=" + warningType +
", createTime=" + createTime +
", updateTime=" + updateTime +
", userId=" + userId +
", userName='" + userName + '\'' +
", releaseState=" + releaseState +
", warningGroupId=" + warningGroupId +
", processInstancePriority=" + processInstancePriority +
", workerGroup='" + workerGroup + '\'' +
'}';
}
public String getDefinitionDescription() {
return definitionDescription;
}
public void setDefinitionDescription(String definitionDescription) {
this.definitionDescription = definitionDescription;
}
@TableId(value = "id", type = IdType.AUTO)
private int id;
/**
* process definition id
*/
private int processDefinitionId;
/**
* process definition name
*/
@TableField(exist = false)
private String processDefinitionName;
/**
* project name
*/
@TableField(exist = false)
private String projectName;
/**
* schedule description
*/
@TableField(exist = false)
private String definitionDescription;
/**
* schedule start time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date startTime;
/**
* schedule end time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date endTime;
/**
* timezoneId
* <p>see {@link java.util.TimeZone#getTimeZone(String)}
*/
private String timezoneId;
/**
* crontab expression
*/
private String crontab;
/**
* failure strategy
*/
private FailureStrategy failureStrategy;
/**
* warning type
*/
private WarningType warningType;
/**
* create time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
/**
* update time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
/**
* created user id
*/
private int userId;
/**
* created user name
*/
@TableField(exist = false)
private String userName;
/**
* release state
*/
private ReleaseState releaseState;
/**
* warning group id
*/
private int warningGroupId;
/**
* process instance priority
*/
private Priority processInstancePriority;
/**
* worker group
*/
private String workerGroup;
public int getWarningGroupId() {
return warningGroupId;
}
public void setWarningGroupId(int warningGroupId) {
this.warningGroupId = warningGroupId;
}
public Schedule() {
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getTimezoneId() {
return timezoneId;
}
public void setTimezoneId(String timezoneId) {
this.timezoneId = timezoneId;
}
public String getCrontab() {
return crontab;
}
public void setCrontab(String crontab) {
this.crontab = crontab;
}
public FailureStrategy getFailureStrategy() {
return failureStrategy;
}
public void setFailureStrategy(FailureStrategy failureStrategy) {
this.failureStrategy = failureStrategy;
}
public WarningType getWarningType() {
return warningType;
}
public void setWarningType(WarningType warningType) {
this.warningType = warningType;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public ReleaseState getReleaseState() {
return releaseState;
}
public void setReleaseState(ReleaseState releaseState) {
this.releaseState = releaseState;
}
public int getProcessDefinitionId() {
return processDefinitionId;
}
public void setProcessDefinitionId(int processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
public String getProcessDefinitionName() {
return processDefinitionName;
}
public void setProcessDefinitionName(String processDefinitionName) {
this.processDefinitionName = processDefinitionName;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Priority getProcessInstancePriority() {
return processInstancePriority;
}
public void setProcessInstancePriority(Priority processInstancePriority) {
this.processInstancePriority = processInstancePriority;
}
public String getWorkerGroup() {
return workerGroup;
}
public void setWorkerGroup(String workerGroup) {
this.workerGroup = workerGroup;
}
@Override
public String toString() {
return "Schedule{"
+ "id=" + id
+ ", processDefinitionId=" + processDefinitionId
+ ", processDefinitionName='" + processDefinitionName + '\''
+ ", projectName='" + projectName + '\''
+ ", description='" + definitionDescription + '\''
+ ", startTime=" + startTime
+ ", endTime=" + endTime
+ ", timezoneId='" + timezoneId + +'\''
+ ", crontab='" + crontab + '\''
+ ", failureStrategy=" + failureStrategy
+ ", warningType=" + warningType
+ ", createTime=" + createTime
+ ", updateTime=" + updateTime
+ ", userId=" + userId
+ ", userName='" + userName + '\''
+ ", releaseState=" + releaseState
+ ", warningGroupId=" + warningGroupId
+ ", processInstancePriority=" + processInstancePriority
+ ", workerGroup='" + workerGroup + '\''
+ '}';
}
public String getDefinitionDescription() {
return definitionDescription;
}
public void setDefinitionDescription(String definitionDescription) {
this.definitionDescription = definitionDescription;
}
}

4
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ScheduleMapper.xml

@ -19,11 +19,11 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.ScheduleMapper">
<sql id="baseSql">
id, process_definition_id, start_time, end_time, crontab, failure_strategy, user_id, release_state,
id, process_definition_id, start_time, end_time, timezone_id, crontab, failure_strategy, user_id, release_state,
warning_type, warning_group_id, process_instance_priority, worker_group, create_time, update_time
</sql>
<sql id="baseSqlV2">
${alias}.id, ${alias}.process_definition_id, ${alias}.start_time, ${alias}.end_time, ${alias}.crontab, ${alias}.failure_strategy, ${alias}.user_id, ${alias}.release_state,
${alias}.id, ${alias}.process_definition_id, ${alias}.start_time, ${alias}.end_time, ${alias}.timezone_id, ${alias}.crontab, ${alias}.failure_strategy, ${alias}.user_id, ${alias}.release_state,
${alias}.warning_type, ${alias}.warning_group_id, ${alias}.process_instance_priority, ${alias}.worker_group, ${alias}.create_time, ${alias}.update_time
</sql>
<select id="queryByProcessDefineIdPaging" resultType="org.apache.dolphinscheduler.dao.entity.Schedule">

1
dolphinscheduler-dist/release-docs/LICENSE vendored

@ -539,6 +539,7 @@ MIT licenses
js-cookie 2.2.1: https://github.com/js-cookie/js-cookie MIT
jsplumb 2.8.6: https://github.com/jsplumb/jsplumb MIT and GPLv2
lodash 4.17.11: https://github.com/lodash/lodash MIT
moment-timezone 0.5.33: https://github.com/moment/moment-timezone MIT
vue-treeselect 0.4.0: https://github.com/riophae/vue-treeselect MIT
vue 2.5.17: https://github.com/vuejs/vue MIT
vue-router 2.7.0: https://github.com/vuejs/vue-router MIT

20
dolphinscheduler-dist/release-docs/licenses/ui-licenses/LICENSE-moment-timezone vendored

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

45
dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/QuartzExecutors.java

@ -60,6 +60,7 @@ import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.common.utils.PropertyUtils;
import org.apache.dolphinscheduler.common.utils.StringUtils;
@ -220,16 +221,18 @@ public class QuartzExecutors {
* add task trigger , if this task already exists, return this task with updated trigger
*
* @param clazz job class name
* @param jobName job name
* @param jobGroupName job group name
* @param startDate job start date
* @param endDate job end date
* @param cronExpression cron expression
* @param jobDataMap job parameters data map
* @param projectId projectId
* @param schedule schedule
*/
public void addJob(Class<? extends Job> clazz, String jobName, String jobGroupName, Date startDate, Date endDate,
String cronExpression,
Map<String, Object> jobDataMap) {
public void addJob(Class<? extends Job> clazz, int projectId, final Schedule schedule) {
String jobName = QuartzExecutors.buildJobName(schedule.getId());
String jobGroupName = QuartzExecutors.buildJobGroupName(projectId);
Date startDate = schedule.getStartTime();
Date endDate = schedule.getEndTime();
Map<String, Object> jobDataMap = QuartzExecutors.buildDataMap(projectId, schedule);
String cronExpression = schedule.getCrontab();
String timezoneId = schedule.getTimezoneId();
lock.writeLock().lock();
try {
@ -239,15 +242,11 @@ public class QuartzExecutors {
if (scheduler.checkExists(jobKey)) {
jobDetail = scheduler.getJobDetail(jobKey);
if (jobDataMap != null) {
jobDetail.getJobDataMap().putAll(jobDataMap);
}
jobDetail.getJobDataMap().putAll(jobDataMap);
} else {
jobDetail = newJob(clazz).withIdentity(jobKey).build();
if (jobDataMap != null) {
jobDetail.getJobDataMap().putAll(jobDataMap);
}
jobDetail.getJobDataMap().putAll(jobDataMap);
scheduler.addJob(jobDetail, false, true);
@ -263,8 +262,15 @@ public class QuartzExecutors {
* current time (taking into account any associated Calendar),
* but it does not want to be fired now.
*/
CronTrigger cronTrigger = newTrigger().withIdentity(triggerKey).startAt(startDate).endAt(endDate)
.withSchedule(cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing())
CronTrigger cronTrigger = newTrigger()
.withIdentity(triggerKey)
.startAt(DateUtils.getTimezoneDate(startDate, timezoneId))
.endAt(DateUtils.getTimezoneDate(endDate, timezoneId))
.withSchedule(
cronSchedule(cronExpression)
.withMisfireHandlingInstructionDoNothing()
.inTimeZone(DateUtils.getTimezone(timezoneId))
)
.forJob(jobDetail).build();
if (scheduler.checkExists(triggerKey)) {
@ -368,14 +374,13 @@ public class QuartzExecutors {
* add params to map
*
* @param projectId project id
* @param scheduleId schedule id
* @param schedule schedule
* @return data map
*/
public static Map<String, Object> buildDataMap(int projectId, int scheduleId, Schedule schedule) {
public static Map<String, Object> buildDataMap(int projectId, Schedule schedule) {
Map<String, Object> dataMap = new HashMap<>(8);
dataMap.put(PROJECT_ID, projectId);
dataMap.put(SCHEDULE_ID, scheduleId);
dataMap.put(SCHEDULE_ID, schedule.getId());
dataMap.put(SCHEDULE, JSONUtils.toJsonString(schedule));
return dataMap;

1
dolphinscheduler-ui/package.json

@ -33,6 +33,7 @@
"js-cookie": "^2.2.1",
"jsplumb": "^2.8.6",
"lodash": "^4.17.11",
"moment-timezone": "^0.5.33",
"normalize.css": "^8.0.1",
"remixicon": "^2.5.0",
"vue": "^2.5.17",

22
dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/timing.vue

@ -61,6 +61,21 @@
</template>
</div>
</div>
<div class="clearfix list">
<div class="text">
{{$t('Timezone')}}
</div>
<div class="cont">
<el-select v-model=timezoneId filterable placeholder="Timezone">
<el-option
v-for="item in availableTimezoneIDList"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</div>
</div>
<div class="clearfix list">
<div style = "padding-left: 150px;">{{$t('Next five execution times')}}</div>
<ul style = "padding-left: 150px;">
@ -144,6 +159,7 @@
</div>
</template>
<script>
import moment from 'moment-timezone'
import i18n from '@/module/i18n'
import store from '@/conf/home/store'
import { warningTypeList } from './util'
@ -160,12 +176,14 @@
processDefinitionId: 0,
failureStrategy: 'CONTINUE',
warningTypeList: warningTypeList,
availableTimezoneIDList: moment.tz.names(),
warningType: 'NONE',
notifyGroupList: [],
warningGroupId: '',
spinnerLoading: false,
scheduleTime: '',
crontab: '0 0 * * * ? *',
timezoneId: moment.tz.guess(),
cronPopover: false,
i18n: i18n.globalScope.LOCALE,
processInstancePriority: 'MEDIUM',
@ -204,7 +222,8 @@
schedule: JSON.stringify({
startTime: this.scheduleTime[0],
endTime: this.scheduleTime[1],
crontab: this.crontab
crontab: this.crontab,
timezoneId: this.timezoneId
}),
failureStrategy: this.failureStrategy,
warningType: this.warningType,
@ -323,6 +342,7 @@
if (this.timingData.item.crontab) {
this.crontab = item.crontab
this.scheduleTime = [formatDate(item.startTime), formatDate(item.endTime)]
this.timezoneId = item.timezoneId === null ? moment.tz.guess() : item.timezoneId
this.failureStrategy = item.failureStrategy
this.warningType = item.warningType
this.processInstancePriority = item.processInstancePriority

1
dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js

@ -399,6 +399,7 @@ export default {
'Import process': 'Import process',
'Timing state': 'Timing state',
Timing: 'Timing',
Timezone: 'Timezone',
TreeView: 'TreeView',
'Mailbox already exists! Recipients and copyers cannot repeat': 'Mailbox already exists! Recipients and copyers cannot repeat',
'Mailbox input is illegal': 'Mailbox input is illegal',

1
dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -399,6 +399,7 @@ export default {
'Import process': '导入工作流',
'Timing state': '定时状态',
Timing: '定时',
Timezone: '时区',
TreeView: '树形图',
'Mailbox already exists! Recipients and copyers cannot repeat': '邮箱已存在收件人和抄送人不能重复',
'Mailbox input is illegal': '邮箱输入不合法',

1
sql/dolphinscheduler_mysql.sql

@ -750,6 +750,7 @@ CREATE TABLE `t_ds_schedules` (
`process_definition_id` int(11) NOT NULL COMMENT 'process definition id',
`start_time` datetime NOT NULL COMMENT 'start time',
`end_time` datetime NOT NULL COMMENT 'end time',
`timezone_id` varchar(40) DEFAULT NULL COMMENT 'timezoneId',
`crontab` varchar(256) NOT NULL COMMENT 'crontab description',
`failure_strategy` tinyint(4) NOT NULL COMMENT 'failure strategy. 0:end,1:continue',
`user_id` int(11) NOT NULL COMMENT 'user id',

1
sql/dolphinscheduler_postgre.sql

@ -614,6 +614,7 @@ CREATE TABLE t_ds_schedules (
process_definition_id int NOT NULL ,
start_time timestamp NOT NULL ,
end_time timestamp NOT NULL ,
timezone_id varchar(40) default NULL ,
crontab varchar(256) NOT NULL ,
failure_strategy int NOT NULL ,
user_id int NOT NULL ,

20
sql/upgrade/1.4.0_schema/mysql/dolphinscheduler_ddl.sql

@ -316,6 +316,26 @@ d//
delimiter ;
CALL uc_dolphin_T_t_ds_datasource_A_add_UN_datasourceName();
DROP PROCEDURE uc_dolphin_T_t_ds_datasource_A_add_UN_datasourceName;
-- uc_dolphin_T_t_ds_schedules_A_add_timezone
drop PROCEDURE if EXISTS uc_dolphin_T_t_ds_schedules_A_add_timezone;
delimiter d//
CREATE PROCEDURE uc_dolphin_T_t_ds_schedules_A_add_timezone()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_NAME='t_ds_schedules'
AND TABLE_SCHEMA=(SELECT DATABASE())
AND COLUMN_NAME ='timezone_id')
THEN
ALTER TABLE t_ds_schedules ADD COLUMN `timezone_id` varchar(40) default NULL COMMENT 'schedule timezone id' AFTER `end_time`;
END IF;
END;
d//
delimiter ;
CALL uc_dolphin_T_t_ds_schedules_A_add_timezone();
DROP PROCEDURE uc_dolphin_T_t_ds_schedules_A_add_timezone;
-- ----------------------------
-- These columns will not be used in the new version,if you determine that the historical data is useless, you can delete it using the sql below
-- ----------------------------

17
sql/upgrade/1.4.0_schema/postgresql/dolphinscheduler_ddl.sql

@ -304,6 +304,23 @@ delimiter ;
SELECT uc_dolphin_T_t_ds_datasource_A_add_UN_datasourceName();
DROP FUNCTION IF EXISTS uc_dolphin_T_t_ds_datasource_A_add_UN_datasourceName();
-- uc_dolphin_T_t_ds_schedules_A_add_timezone
delimiter d//
CREATE OR REPLACE FUNCTION uc_dolphin_T_t_ds_schedules_A_add_timezone() RETURNS void AS $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_NAME='t_ds_schedules'
AND COLUMN_NAME ='timezone_id')
THEN
ALTER TABLE t_ds_schedules ADD COLUMN timezone_id varchar(40) DEFAULT NULL;
END IF;
END;
$$ LANGUAGE plpgsql;
d//
delimiter ;
SELECT uc_dolphin_T_t_ds_schedules_A_add_timezone();
DROP FUNCTION IF EXISTS uc_dolphin_T_t_ds_schedules_A_add_timezone();
-- ----------------------------
-- These columns will not be used in the new version,if you determine that the historical data is useless, you can delete it using the sql below
-- ----------------------------

Loading…
Cancel
Save