Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(scheduler): add support for scheduler #26

Merged
merged 87 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
2a44680
创建分支
andylau-55 Nov 29, 2023
720a872
init Scheduler Model
andylau-55 Nov 30, 2023
7539535
init Scheduler api
andylau-55 Nov 30, 2023
de546c5
init Scheduler task
andylau-55 Nov 30, 2023
403ced6
init Scheduler metadata
andylau-55 Nov 30, 2023
9bf1a5a
init Scheduler Handler
andylau-55 Nov 30, 2023
4dcd829
init Scheduler Handler
andylau-55 Dec 1, 2023
c489e14
init Scheduler Handler
andylau-55 Dec 1, 2023
f3b06a8
Scheduler metadata Local impl
andylau-55 Dec 1, 2023
eb6366d
Scheduler metadata Local impl
andylau-55 Dec 1, 2023
a76184e
Scheduler metadata Local impl
andylau-55 Dec 4, 2023
93231e5
Scheduler query init
andylau-55 Dec 4, 2023
a5992b8
Scheduler query optimize
andylau-55 Dec 4, 2023
0ff0d25
Scheduler engine impl
andylau-55 Dec 5, 2023
ba85058
Scheduler DryRun impl
andylau-55 Dec 5, 2023
3c7b3bb
Scheduler DryRun impl
andylau-55 Dec 5, 2023
48ebd6e
Scheduler generateInstances impl
andylau-55 Dec 5, 2023
a9167e5
Scheduler generateInstance impl
andylau-55 Dec 6, 2023
356f48f
Scheduler SchedulerService impl
andylau-55 Dec 6, 2023
267ccc5
Scheduler unit test impl
andylau-55 Dec 6, 2023
2bfeb14
Scheduler unit test impl
andylau-55 Dec 7, 2023
16307aa
Scheduler unit test impl
andylau-55 Dec 7, 2023
5a57bbe
Scheduler unit test impl
andylau-55 Dec 7, 2023
5d2aaec
Scheduler unit test impl
andylau-55 Dec 7, 2023
a57364c
Scheduler unit test impl
andylau-55 Dec 8, 2023
46245a0
Merge branch 'master' into andy_1129
andylau-55 Dec 11, 2023
d2ab5dc
pom fix
andylau-55 Dec 11, 2023
5dd3a93
license
andylau-55 Dec 11, 2023
2a9f517
mvn spotless:apply
andylau-55 Dec 12, 2023
fa9b8ce
IpUtils
andylau-55 Dec 12, 2023
50219c5
test
andylau-55 Dec 12, 2023
53025df
PR repair
andylau-55 Dec 12, 2023
64a8a37
PR repair
andylau-55 Dec 12, 2023
dc5f1c4
spotless:apply
andylau-55 Dec 12, 2023
2abf885
spotless:apply
andylau-55 Dec 12, 2023
5b866d6
spotless:apply
andylau-55 Dec 12, 2023
328d1cd
spotless:apply
andylau-55 Dec 12, 2023
77d62d5
spotless:apply
andylau-55 Dec 12, 2023
2c675f9
spotless:apply
andylau-55 Dec 12, 2023
b285c76
PR repair
andylau-55 Dec 13, 2023
c7be6a5
spotless:apply
andylau-55 Dec 13, 2023
6f24393
add SchedulerException
andylau-55 Dec 13, 2023
0b085bc
add SchedulerException
andylau-55 Dec 13, 2023
6506325
add SchedulerException
andylau-55 Dec 13, 2023
4b997aa
spotless:apply
andylau-55 Dec 13, 2023
71fe6b8
optimizer
andylau-55 Dec 13, 2023
5f8d579
optimizer
andylau-55 Dec 13, 2023
ed85e26
optimizer
andylau-55 Dec 13, 2023
8290d86
optimizer
andylau-55 Dec 14, 2023
bd150d5
optimizer
andylau-55 Dec 14, 2023
3df74c1
optimizer
andylau-55 Dec 14, 2023
caf32e5
optimizer
andylau-55 Dec 14, 2023
a87d7b2
optimizer
andylau-55 Dec 14, 2023
1bc932f
optimizer
andylau-55 Dec 14, 2023
2c769b0
optimizer
andylau-55 Dec 14, 2023
4701f79
optimizer
andylau-55 Dec 14, 2023
dbf06dc
optimizer
andylau-55 Dec 15, 2023
d32ac4b
optimizer
andylau-55 Dec 15, 2023
9077a50
mock
andylau-55 Dec 15, 2023
37286c7
optimizer
andylau-55 Dec 15, 2023
290405b
optimizer
andylau-55 Dec 15, 2023
237ca6c
optimizer
andylau-55 Dec 15, 2023
60a4128
mock
andylau-55 Dec 15, 2023
b5e987e
mock
andylau-55 Dec 15, 2023
0a59b07
TaskExecute
andylau-55 Dec 15, 2023
b822e9f
TaskExecute
andylau-55 Dec 15, 2023
3844bce
spotless:apply
andylau-55 Dec 15, 2023
124ce0e
optimizer
andylau-55 Dec 15, 2023
781c9bf
TaskExecute
andylau-55 Dec 15, 2023
6d86218
spotless:apply
andylau-55 Dec 15, 2023
003efa6
Transactional
andylau-55 Dec 15, 2023
d6e4442
Transactional
andylau-55 Dec 15, 2023
bdaaa59
Transactional
andylau-55 Dec 15, 2023
4d22f56
spotless:apply
andylau-55 Dec 18, 2023
5db4cca
spotless:apply
andylau-55 Dec 18, 2023
88e3058
@ConditionalOnProperty
andylau-55 Dec 18, 2023
130dc21
@ConditionalOnProperty
andylau-55 Dec 18, 2023
b0ce0a1
sls
andylau-55 Dec 19, 2023
d24259c
traceLog
andylau-55 Dec 19, 2023
b63484e
add comments
andylau-55 Dec 27, 2023
7e5ebca
add comments
andylau-55 Dec 27, 2023
d35de28
add comments
andylau-55 Jan 2, 2024
2e42a65
add comments
andylau-55 Jan 2, 2024
ef23c52
add comments
andylau-55 Jan 2, 2024
8c7126f
merge master #andy
andylau-55 Nov 18, 2024
aaa6f96
merge master #andy
andylau-55 Nov 18, 2024
be68c8c
merge master #andy
andylau-55 Nov 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions common/util/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,9 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,17 @@ public static String bizDateByNow() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YYYY_MM_DD1);
return simpleDateFormat.format(new Date());
}

/** Date to String by yyyy-MM-dd HH:mm:ss */
public static String getDate2LongStr(Date date) {
return getDate2Str(YYYY_MM_DD_HH_MM_SS1, date);
}

/** Date to String by format */
public static String getDate2Str(String format, Date date) {
if (date == null) {
return "";
}
return new SimpleDateFormat(format).format(date);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright 2023 Ant Group CO., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied.
*/
package com.antgroup.openspg.common.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.quartz.CronExpression;

/** some common tools */
@Slf4j
public class SchedulerUtils {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个类是不是直接放在core/scheduler/service就ok了?同时需要增加一些单测

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

集成测试中已经包含了该方法的单侧


public static final String IPS = String.join(",", getLocalIps());
public static final String EQ = "eq";
public static final String IN = "in";
public static final String LT = "lt";

/** merge two bean by discovering differences */
public static <M> M merge(M dest, M orig) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个方法不是SchedulerUtils?而应该放在BeanUtils呢?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

调度的本地查询merge逻辑,只有为目标值空才会覆盖,不适合放到BeanUtils

if (dest == null || orig == null) {
return (dest == null) ? orig : dest;
}
try {
BeanInfo beanInfo = Introspector.getBeanInfo(dest.getClass());
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
if (descriptor.getWriteMethod() == null) {
continue;
}
Object originalValue = descriptor.getReadMethod().invoke(orig);
if (originalValue == null) {
continue;
}
descriptor.getWriteMethod().invoke(dest, originalValue);
}
} catch (Exception e) {
log.error("merge bean exception", e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个merge失败要抛异常的,不然异常吞了上游要得到非预期结果

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为入参都是同一类型M,这里反射不会抛出异常。

}
return dest;
}

/** Limit remark. sub String To Length */
public static String setRemarkLimit(String oldRemark, StringBuffer appendRemark) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个方法命名感觉也不太对。太定制化了是不是不需要放在common/util?直接scheduler包那里使用就ok了

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

静态的工具方法统一放在SchedulerUtils.java类中,供Scheduler统一调用是合理的吧

Integer start = 0;
Integer length = 100000;
StringBuffer str = appendRemark.append(oldRemark);
String fill = "...";
if (length >= str.length()) {
return str.toString();
}
return str.substring(start, length - fill.length()) + fill;
}

/** get CronExpression */
public static CronExpression getCronExpression(String cron) {
try {
return new CronExpression(cron);
} catch (ParseException e) {
throw new RuntimeException("Cron ParseException:" + cron, e);
}
}

/** get Cron Execution Dates By Today */
public static List<Date> getCronExecutionDatesByToday(String cron) {
CronExpression expression = getCronExpression(cron);
List<Date> dates = new ArrayList<>();
Date startDate = DateUtils.truncate(new Date(), Calendar.DAY_OF_MONTH);
Date endDate = DateUtils.addDays(startDate, 1);

if (expression.isSatisfiedBy(startDate)) {
dates.add(startDate);
}
Date nextDate = expression.getNextValidTimeAfter(startDate);
while (nextDate != null && nextDate.before(endDate)) {
dates.add(nextDate);
nextDate = expression.getNextValidTimeAfter(nextDate);
}

return dates;
}

/** get Previous ValidTime */
public static Date getPreviousValidTime(String cron, Date date) {
CronExpression expression = getCronExpression(cron);
Date endDate = expression.getNextValidTimeAfter(expression.getNextValidTimeAfter(date));
Long time = 2 * date.getTime() - endDate.getTime();

Date nextDate = expression.getNextValidTimeAfter(new Date(time));
Date preDate = nextDate;
while (nextDate != null && nextDate.before(date)) {
preDate = nextDate;
nextDate = expression.getNextValidTimeAfter(nextDate);
}
return preDate;
}

/** get Unique Id */
public static String getUniqueId(Long jobId, Date schedulerDate) {
return jobId + DateTimeUtils.getDate2Str(DateTimeUtils.YYYY_MM_DD_HH_MM_SS2, schedulerDate);
}

/** content compare key */
public static boolean compare(Object content, Object key, String type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个方法太定制化了,不像是common/util呢。key/content有可能是 Date或者String类型。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scheduler用于对象属性比较的,提供给Scheduler的本地查询用,所以统一放在SchedulerUtils中

if (key == null) {
return true;
}
if (content == null) {
return false;
}
switch (type) {
case EQ:
return content.equals(key);
case IN:
return ((String) content).contains((String) key);
case LT:
return ((Date) key).before((Date) content);
default:
return false;
}
}

/** get local ips */
public static List<String> getLocalIps() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个方法NetworkAddressUtils里面已经有了

try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
return Collections.list(networkInterfaces).stream()
.flatMap(network -> Collections.list(network.getInetAddresses()).stream())
.filter(address -> address instanceof Inet4Address && !address.isLoopbackAddress())
.map(InetAddress::getHostAddress)
.collect(Collectors.toList());
} catch (SocketException e) {
log.error("getLocalIps failed.", e);
}
return new ArrayList<>();
}
}
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@
<artifactId>QLExpress</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ cloudext.repository.impl.jdbc.port=3306
cloudext.repository.impl.jdbc.username=root
cloudext.repository.impl.jdbc.password=openspg
cloudext.repository.impl.jdbc.driver=com.mysql.jdbc.Driver

# Scheduler
scheduler.handler.type=local
scheduler.execute.instances.period=5
scheduler.execute.instances.unit=MINUTES
scheduler.generate.instances.period=1
scheduler.generate.instances.unit=HOURS
scheduler.execute.max.day=10
4 changes: 4 additions & 0 deletions server/common/model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,9 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2023 Ant Group CO., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied.
*/
package com.antgroup.openspg.server.common.model.exception;

/** Scheduler exception */
public class SchedulerException extends OpenSPGException {

public SchedulerException(String message, Object... args) {
super(null, true, true, message, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2023 Ant Group CO., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied.
*/
package com.antgroup.openspg.server.common.model.scheduler;

/** all scheduler dependent enum */
public interface SchedulerEnum {

/** Instance Status enum */
enum InstanceStatus {
WAITING,
RUNNING,
SKIP,
FINISH,
TERMINATE,
SET_FINISH;

/** status is Finished */
public static boolean isFinished(InstanceStatus status) {
return InstanceStatus.FINISH.equals(status)
|| InstanceStatus.TERMINATE.equals(status)
|| InstanceStatus.SET_FINISH.equals(status)
|| InstanceStatus.SKIP.equals(status);
}
}

/** Life Cycle Enum */
enum LifeCycle {
PERIOD,
ONCE,
REAL_TIME
}

/** Dependence Enum */
enum Dependence {
DEPENDENT,
INDEPENDENT
}

/** Status Enum */
enum Status {
ENABLE,
DISABLE
}

/** Task Status Enum */
enum TaskStatus {
WAIT,
RUNNING,
FINISH,
ERROR,
SKIP,
TERMINATE,
SET_FINISH;

/** status is Finished by TaskStatus */
public static boolean isFinished(TaskStatus status) {
return TaskStatus.FINISH.equals(status)
|| TaskStatus.SKIP.equals(status)
|| TaskStatus.TERMINATE.equals(status)
|| TaskStatus.SET_FINISH.equals(status);
}

/** status is Running by TaskStatus */
public static boolean isRunning(TaskStatus status) {
return TaskStatus.RUNNING.equals(status) || TaskStatus.ERROR.equals(status);
}
}

/** Translate Enum */
enum TranslateType {
LOCAL_EXAMPLE("localExampleTranslate");

private String type;

TranslateType(String type) {
this.type = type;
}

public String getType() {
return type;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ public static <T> T getBean(Class<T> clazz) {
return null;
}

/** get spring bean by name */
public static <T> T getBean(String name, Class<T> clazz) {
if (applicationContext != null) {
return applicationContext.getBean(name, clazz);
}
return null;
}

public static <T> List<T> getBeans(Class<T> clazz) {
if (applicationContext != null) {
return new ArrayList<>(applicationContext.getBeansOfType(clazz).values());
Expand Down
39 changes: 39 additions & 0 deletions server/core/scheduler/model/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2023 Ant Group CO., Ltd.
~
~ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software distributed under the License
~ is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
~ or implied.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.antgroup.openspg.server</groupId>
<artifactId>server-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>

<artifactId>core-scheduler-model</artifactId>
<dependencies>
<dependency>
<groupId>com.antgroup.openspg.server</groupId>
<artifactId>common-model</artifactId>
</dependency>
<dependency>
<groupId>com.antgroup.openspg</groupId>
<artifactId>common-util</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
</project>
Loading
Loading