mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-11-29 18:48:23 +08:00
feat(plugin): adapter scheduler -- local
This commit is contained in:
parent
a2a7cb5b10
commit
e14fc43ac2
@ -6,4 +6,5 @@ datacap-convert-xml=convert/datacap-convert-xml/pom.xml
|
|||||||
datacap-convert-csv=convert/datacap-convert-csv/pom.xml
|
datacap-convert-csv=convert/datacap-convert-csv/pom.xml
|
||||||
datacap-convert-none=convert/datacap-convert-none/pom.xml
|
datacap-convert-none=convert/datacap-convert-none/pom.xml
|
||||||
datacap-executor-local=executor/datacap-executor-local/pom.xml
|
datacap-executor-local=executor/datacap-executor-local/pom.xml
|
||||||
datacap-executor-seatunnel=executor/datacap-executor-seatunnel/pom.xml
|
datacap-executor-seatunnel=executor/datacap-executor-seatunnel/pom.xml
|
||||||
|
datacap-scheduler-local=scheduler/datacap-scheduler-local/pom.xml
|
@ -139,6 +139,21 @@
|
|||||||
"ALL"
|
"ALL"
|
||||||
],
|
],
|
||||||
"url": "https://cdn.north.devlive.org/applications/datacap/plugins/2024.4.0-SNAPSHOT/executor/datacap-executor-seatunnel-bin.tar.gz"
|
"url": "https://cdn.north.devlive.org/applications/datacap/plugins/2024.4.0-SNAPSHOT/executor/datacap-executor-seatunnel-bin.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "datacap-scheduler-local",
|
||||||
|
"label": "LocalScheduler",
|
||||||
|
"description": "A local scheduling plugin for DataCap.",
|
||||||
|
"i18nFormat": true,
|
||||||
|
"type": "Scheduler",
|
||||||
|
"version": "2024.4.0-SNAPSHOT",
|
||||||
|
"author": "datacap-community",
|
||||||
|
"logo": "https://cdn.north.devlive.org/applications/datacap/resources/logo/scheduler/local.svg",
|
||||||
|
"released": "2024-11-21 23:11:15",
|
||||||
|
"supportVersion": [
|
||||||
|
"ALL"
|
||||||
|
],
|
||||||
|
"url": "https://cdn.north.devlive.org/applications/datacap/plugins/2024.4.0-SNAPSHOT/scheduler/datacap-scheduler-local-bin.tar.gz"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -11,3 +11,13 @@ WHERE `version` IS NULL;
|
|||||||
UPDATE `datacap_dataset`
|
UPDATE `datacap_dataset`
|
||||||
SET `executor` = 'LocalExecutor'
|
SET `executor` = 'LocalExecutor'
|
||||||
WHERE `executor` = 'Default';
|
WHERE `executor` = 'Default';
|
||||||
|
|
||||||
|
ALTER TABLE `datacap_dataset`
|
||||||
|
ALTER COLUMN `executor` SET DEFAULT 'LocalExecutor';
|
||||||
|
|
||||||
|
UPDATE `datacap_dataset`
|
||||||
|
SET `scheduler` = 'LocalScheduler'
|
||||||
|
WHERE `scheduler` = 'Default';
|
||||||
|
|
||||||
|
ALTER TABLE `datacap_dataset`
|
||||||
|
ALTER COLUMN `scheduler` SET DEFAULT 'LocalScheduler';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.edurt.datacap.plugin;
|
package io.edurt.datacap.plugin;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -11,6 +12,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Builder
|
@Builder
|
||||||
|
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
|
||||||
public class PluginConfigure
|
public class PluginConfigure
|
||||||
{
|
{
|
||||||
private static final Set<String> LOADER_PACKAGES = Set.of(
|
private static final Set<String> LOADER_PACKAGES = Set.of(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.edurt.datacap.plugin.loader;
|
package io.edurt.datacap.plugin.loader;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import java.util.Set;
|
|||||||
* Plugin-specific ClassLoader
|
* Plugin-specific ClassLoader
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@SuppressFBWarnings(value = {"EI_EXPOSE_REP2"})
|
||||||
public class PluginClassLoader
|
public class PluginClassLoader
|
||||||
extends URLClassLoader
|
extends URLClassLoader
|
||||||
implements AutoCloseable
|
implements AutoCloseable
|
||||||
|
@ -500,7 +500,6 @@
|
|||||||
<!-- <version>${project.version}</version>-->
|
<!-- <version>${project.version}</version>-->
|
||||||
<!-- <scope>provided</scope>-->
|
<!-- <scope>provided</scope>-->
|
||||||
<!-- </dependency>-->
|
<!-- </dependency>-->
|
||||||
<!-- Executor -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.edurt.datacap</groupId>
|
<groupId>io.edurt.datacap</groupId>
|
||||||
<artifactId>datacap-executor-spi</artifactId>
|
<artifactId>datacap-executor-spi</artifactId>
|
||||||
@ -511,13 +510,6 @@
|
|||||||
<artifactId>datacap-scheduler-spi</artifactId>
|
<artifactId>datacap-scheduler-spi</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
|
||||||
<!-- <artifactId>datacap-scheduler-local</artifactId>-->
|
|
||||||
<!-- <version>${project.version}</version>-->
|
|
||||||
<!-- <scope>provided</scope>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
<!-- Convert -->
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -12,7 +12,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
|||||||
@EnableAsync
|
@EnableAsync
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ScheduleConfiguration
|
public class SchedulerConfiguration
|
||||||
{
|
{
|
||||||
@Bean
|
@Bean
|
||||||
public TaskScheduler taskScheduler()
|
public TaskScheduler taskScheduler()
|
@ -0,0 +1,62 @@
|
|||||||
|
package io.edurt.datacap.server.runner;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
import io.edurt.datacap.plugin.PluginManager;
|
||||||
|
import io.edurt.datacap.scheduler.SchedulerRequest;
|
||||||
|
import io.edurt.datacap.scheduler.SchedulerService;
|
||||||
|
import io.edurt.datacap.service.enums.SyncMode;
|
||||||
|
import io.edurt.datacap.service.initializer.job.DatasetJob;
|
||||||
|
import io.edurt.datacap.service.repository.DataSetRepository;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
|
||||||
|
public class SchedulerRunner
|
||||||
|
implements CommandLineRunner
|
||||||
|
{
|
||||||
|
private final PluginManager pluginManager;
|
||||||
|
private final DataSetRepository repository;
|
||||||
|
private final Scheduler scheduler;
|
||||||
|
|
||||||
|
public SchedulerRunner(PluginManager pluginManager, DataSetRepository repository, Scheduler scheduler)
|
||||||
|
{
|
||||||
|
this.pluginManager = pluginManager;
|
||||||
|
this.repository = repository;
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args)
|
||||||
|
{
|
||||||
|
log.info("Start scheduler initializer");
|
||||||
|
repository.findAllBySyncMode(SyncMode.TIMING)
|
||||||
|
.forEach(item -> {
|
||||||
|
log.info("Dataset [ {} ] will be scheduled", item.getName());
|
||||||
|
pluginManager.getPlugin(item.getScheduler())
|
||||||
|
.ifPresentOrElse(
|
||||||
|
plugin -> {
|
||||||
|
SchedulerRequest request = SchedulerRequest.builder()
|
||||||
|
.name(item.getCode())
|
||||||
|
.group("datacap")
|
||||||
|
.expression(item.getExpression())
|
||||||
|
.jobId(item.getCode())
|
||||||
|
.createBeforeDelete(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
SchedulerService schedulerService = plugin.getService(SchedulerService.class);
|
||||||
|
if (item.getScheduler().equalsIgnoreCase("LocalScheduler")) {
|
||||||
|
request.setJob(new DatasetJob());
|
||||||
|
request.setScheduler(this.scheduler);
|
||||||
|
}
|
||||||
|
schedulerService.initialize(request);
|
||||||
|
},
|
||||||
|
() -> log.error("Scheduler [ {} ] not found", item.getScheduler())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
log.info("End scheduler initializer");
|
||||||
|
}
|
||||||
|
}
|
@ -1,62 +0,0 @@
|
|||||||
package io.edurt.datacap.service.initializer;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import io.edurt.datacap.plugin.PluginManager;
|
|
||||||
import io.edurt.datacap.scheduler.SchedulerRequest;
|
|
||||||
import io.edurt.datacap.scheduler.SchedulerService;
|
|
||||||
import io.edurt.datacap.service.enums.SyncMode;
|
|
||||||
import io.edurt.datacap.service.initializer.job.DatasetJob;
|
|
||||||
import io.edurt.datacap.service.repository.DataSetRepository;
|
|
||||||
import io.edurt.datacap.service.service.DataSetService;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.quartz.Scheduler;
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
|
|
||||||
public class DatasetSchedulerInitializer
|
|
||||||
implements CommandLineRunner
|
|
||||||
{
|
|
||||||
private final PluginManager pluginManager;
|
|
||||||
private final DataSetRepository repository;
|
|
||||||
private final DataSetService service;
|
|
||||||
private final Scheduler scheduler;
|
|
||||||
|
|
||||||
public DatasetSchedulerInitializer(PluginManager pluginManager, DataSetRepository repository, DataSetService service, Scheduler scheduler)
|
|
||||||
{
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
this.repository = repository;
|
|
||||||
this.service = service;
|
|
||||||
this.scheduler = scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String... args)
|
|
||||||
throws Exception
|
|
||||||
{
|
|
||||||
log.info("Start dataset scheduler initializer");
|
|
||||||
this.repository.findAllBySyncMode(SyncMode.TIMING)
|
|
||||||
.forEach(item -> {
|
|
||||||
log.info("Dataset [ {} ] will be scheduled", item.getName());
|
|
||||||
pluginManager.getPlugin(item.getScheduler())
|
|
||||||
.ifPresent(scheduler -> {
|
|
||||||
SchedulerRequest request = new SchedulerRequest();
|
|
||||||
request.setName(item.getCode());
|
|
||||||
request.setGroup("datacap");
|
|
||||||
request.setExpression(item.getExpression());
|
|
||||||
request.setJobId(item.getCode());
|
|
||||||
request.setCreateBeforeDelete(true);
|
|
||||||
|
|
||||||
SchedulerService schedulerService = scheduler.getService(SchedulerService.class);
|
|
||||||
if (schedulerService.name().equals("Default")) {
|
|
||||||
request.setJob(new DatasetJob());
|
|
||||||
request.setScheduler(this.scheduler);
|
|
||||||
}
|
|
||||||
schedulerService.initialize(request);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
log.info("End dataset scheduler initializer");
|
|
||||||
}
|
|
||||||
}
|
|
@ -772,16 +772,17 @@ public class DataSetServiceImpl
|
|||||||
log.info("Start schedule for dataset [ {} ] id [ {} ]", entity.getName(), entity.getId());
|
log.info("Start schedule for dataset [ {} ] id [ {} ]", entity.getName(), entity.getId());
|
||||||
if (entity.getSyncMode().equals(SyncMode.TIMING)) {
|
if (entity.getSyncMode().equals(SyncMode.TIMING)) {
|
||||||
pluginManager.getPlugin(entity.getScheduler())
|
pluginManager.getPlugin(entity.getScheduler())
|
||||||
.ifPresent(scheduler -> {
|
.ifPresent(plugin -> {
|
||||||
SchedulerRequest request = new SchedulerRequest();
|
SchedulerRequest request = SchedulerRequest.builder()
|
||||||
request.setName(entity.getCode());
|
.name(entity.getCode())
|
||||||
request.setGroup("datacap");
|
.group("datacap")
|
||||||
request.setExpression(entity.getExpression());
|
.expression(entity.getExpression())
|
||||||
request.setJobId(entity.getCode());
|
.jobId(entity.getCode())
|
||||||
request.setCreateBeforeDelete(true);
|
.createBeforeDelete(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
SchedulerService schedulerService = scheduler.getService(SchedulerService.class);
|
SchedulerService schedulerService = plugin.getService(SchedulerService.class);
|
||||||
if (schedulerService.name().equals("Default")) {
|
if (entity.getScheduler().equalsIgnoreCase("LocalScheduler")) {
|
||||||
request.setJob(new DatasetJob());
|
request.setJob(new DatasetJob());
|
||||||
request.setScheduler(this.scheduler);
|
request.setScheduler(this.scheduler);
|
||||||
}
|
}
|
||||||
@ -790,13 +791,14 @@ public class DataSetServiceImpl
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pluginManager.getPlugin(entity.getScheduler())
|
pluginManager.getPlugin(entity.getScheduler())
|
||||||
.ifPresent(scheduler -> {
|
.ifPresent(plugin -> {
|
||||||
SchedulerRequest request = new SchedulerRequest();
|
SchedulerRequest request = SchedulerRequest.builder()
|
||||||
request.setName(entity.getCode());
|
.name(entity.getCode())
|
||||||
request.setGroup("datacap");
|
.group("datacap")
|
||||||
|
.build();
|
||||||
|
|
||||||
SchedulerService schedulerService = scheduler.getService(SchedulerService.class);
|
SchedulerService schedulerService = plugin.getService(SchedulerService.class);
|
||||||
if (schedulerService.name().equals("Default")) {
|
if (entity.getScheduler().equalsIgnoreCase("LocalScheduler")) {
|
||||||
request.setScheduler(this.scheduler);
|
request.setScheduler(this.scheduler);
|
||||||
}
|
}
|
||||||
schedulerService.stop(request);
|
schedulerService.stop(request);
|
||||||
|
@ -220,7 +220,7 @@
|
|||||||
<ShadcnFormItem name="scheduler" :label="$t('common.scheduler')">
|
<ShadcnFormItem name="scheduler" :label="$t('common.scheduler')">
|
||||||
<ShadcnSelect v-model="formState.scheduler" name="scheduler">
|
<ShadcnSelect v-model="formState.scheduler" name="scheduler">
|
||||||
<template #options>
|
<template #options>
|
||||||
<ShadcnSelectOption v-for="item in schedulers" :label="item" :value="item"/>
|
<ShadcnSelectOption v-for="item in schedulers" :label="item.name" :value="item.name"/>
|
||||||
</template>
|
</template>
|
||||||
</ShadcnSelect>
|
</ShadcnSelect>
|
||||||
</ShadcnFormItem>
|
</ShadcnFormItem>
|
||||||
|
29
logo/scheduler/local.svg
Normal file
29
logo/scheduler/local.svg
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
|
||||||
|
<!-- 背景圆形 -->
|
||||||
|
<!-- Background circle -->
|
||||||
|
<circle cx="120" cy="120" r="120" fill="#4A90E2" />
|
||||||
|
|
||||||
|
<!-- 计算机显示器主体 -->
|
||||||
|
<!-- Computer monitor body -->
|
||||||
|
<rect x="60" y="70" width="120" height="80" rx="4" fill="white" />
|
||||||
|
|
||||||
|
<!-- 显示器支架 -->
|
||||||
|
<!-- Monitor stand -->
|
||||||
|
<rect x="110" y="150" width="20" height="10" fill="white" />
|
||||||
|
<rect x="95" y="160" width="50" height="4" rx="2" fill="white" />
|
||||||
|
|
||||||
|
<!-- 时钟图案 -->
|
||||||
|
<!-- Clock pattern -->
|
||||||
|
<circle cx="120" cy="110" r="25" fill="#4A90E2" stroke="white" stroke-width="4" />
|
||||||
|
<line x1="120" y1="110" x2="120" y2="95" stroke="white" stroke-width="4" stroke-linecap="round" />
|
||||||
|
<line x1="120" y1="110" x2="130" y2="110" stroke="white" stroke-width="4" stroke-linecap="round" />
|
||||||
|
|
||||||
|
<!-- 齿轮装饰 -->
|
||||||
|
<!-- Gear decoration -->
|
||||||
|
<circle cx="170" cy="180" r="15" fill="white" />
|
||||||
|
<path d="M170,165 L173,180 L170,195 L167,180 Z" fill="#4A90E2" />
|
||||||
|
<path d="M155,180 L170,177 L185,180 L170,183 Z" fill="#4A90E2" />
|
||||||
|
<path d="M158,168 L172,178 L182,192 L168,182 Z" fill="#4A90E2" />
|
||||||
|
<path d="M158,192 L168,178 L182,168 L172,182 Z" fill="#4A90E2" />
|
||||||
|
<circle cx="170" cy="180" r="5" fill="#4A90E2" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
4
pom.xml
4
pom.xml
@ -92,7 +92,7 @@
|
|||||||
<!-- <module>parser/datacap-parser-trino</module>-->
|
<!-- <module>parser/datacap-parser-trino</module>-->
|
||||||
<!-- <module>parser/datacap-parser-mysql</module>-->
|
<!-- <module>parser/datacap-parser-mysql</module>-->
|
||||||
<module>scheduler/datacap-scheduler-spi</module>
|
<module>scheduler/datacap-scheduler-spi</module>
|
||||||
<!-- <module>scheduler/datacap-scheduler-local</module>-->
|
<module>scheduler/datacap-scheduler-local</module>
|
||||||
<module>notify/datacap-notify-spi</module>
|
<module>notify/datacap-notify-spi</module>
|
||||||
<!-- <module>notify/datacap-notify-dingtalk</module>-->
|
<!-- <module>notify/datacap-notify-dingtalk</module>-->
|
||||||
<module>convert/datacap-convert-spi</module>
|
<module>convert/datacap-convert-spi</module>
|
||||||
@ -106,6 +106,7 @@
|
|||||||
<module>test/datacap-test-core</module>
|
<module>test/datacap-test-core</module>
|
||||||
<module>test/datacap-test-lib</module>
|
<module>test/datacap-test-lib</module>
|
||||||
<module>test/datacap-test-executor</module>
|
<module>test/datacap-test-executor</module>
|
||||||
|
<module>test/datacap-test-scheduler</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<name>datacap</name>
|
<name>datacap</name>
|
||||||
@ -194,6 +195,7 @@
|
|||||||
<useragent.version>1.21</useragent.version>
|
<useragent.version>1.21</useragent.version>
|
||||||
<openai.version>2024.01.3</openai.version>
|
<openai.version>2024.01.3</openai.version>
|
||||||
<testcontainers.version>1.20.1</testcontainers.version>
|
<testcontainers.version>1.20.1</testcontainers.version>
|
||||||
|
<quartz.version>2.3.2</quartz.version>
|
||||||
<assembly-plugin.version>3.6.0</assembly-plugin.version>
|
<assembly-plugin.version>3.6.0</assembly-plugin.version>
|
||||||
<dep.reflections.version>0.10.2</dep.reflections.version>
|
<dep.reflections.version>0.10.2</dep.reflections.version>
|
||||||
<!-- datacap plugin dependency -->
|
<!-- datacap plugin dependency -->
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package io.edurt.datacap.scheduler.local
|
|
||||||
|
|
||||||
import com.google.inject.multibindings.Multibinder
|
|
||||||
import io.edurt.datacap.scheduler.Scheduler
|
|
||||||
import io.edurt.datacap.scheduler.SchedulerModule
|
|
||||||
|
|
||||||
class LocalSchedulerModule : SchedulerModule() {
|
|
||||||
override fun name(): String {
|
|
||||||
return "Default"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun configure() {
|
|
||||||
Multibinder.newSetBinder(this.binder(), Scheduler::class.java)
|
|
||||||
.addBinding()
|
|
||||||
.to(LocalScheduler::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.edurt.datacap.scheduler.local
|
||||||
|
|
||||||
|
import io.edurt.datacap.plugin.Plugin
|
||||||
|
import io.edurt.datacap.plugin.PluginType
|
||||||
|
|
||||||
|
class LocalSchedulerPlugin : Plugin()
|
||||||
|
{
|
||||||
|
override fun getType(): PluginType
|
||||||
|
{
|
||||||
|
return PluginType.SCHEDULER
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,18 @@
|
|||||||
package io.edurt.datacap.scheduler.local
|
package io.edurt.datacap.scheduler.local
|
||||||
|
|
||||||
import io.edurt.datacap.scheduler.Scheduler
|
|
||||||
import io.edurt.datacap.scheduler.SchedulerRequest
|
import io.edurt.datacap.scheduler.SchedulerRequest
|
||||||
import io.edurt.datacap.scheduler.SchedulerResponse
|
import io.edurt.datacap.scheduler.SchedulerResponse
|
||||||
|
import io.edurt.datacap.scheduler.SchedulerService
|
||||||
|
|
||||||
class LocalScheduler : Scheduler {
|
class LocalSchedulerService : SchedulerService
|
||||||
override fun name(): String {
|
{
|
||||||
return "Default"
|
override fun initialize(request: SchedulerRequest): SchedulerResponse
|
||||||
}
|
{
|
||||||
|
|
||||||
override fun initialize(request: SchedulerRequest): SchedulerResponse {
|
|
||||||
return QuartzEndpoint.createJob(request)
|
return QuartzEndpoint.createJob(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stop(request: SchedulerRequest): SchedulerResponse {
|
override fun stop(request: SchedulerRequest): SchedulerResponse
|
||||||
|
{
|
||||||
return QuartzEndpoint.removeJob(request)
|
return QuartzEndpoint.removeJob(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,19 +5,23 @@ import io.edurt.datacap.scheduler.SchedulerResponse
|
|||||||
import org.quartz.*
|
import org.quartz.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
object QuartzEndpoint
|
||||||
object QuartzEndpoint {
|
{
|
||||||
private val log = LoggerFactory.getLogger(this.javaClass)
|
private val log = LoggerFactory.getLogger(this.javaClass)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createJob(request: SchedulerRequest): SchedulerResponse {
|
fun createJob(request: SchedulerRequest): SchedulerResponse
|
||||||
|
{
|
||||||
val response = SchedulerResponse()
|
val response = SchedulerResponse()
|
||||||
val name = getJobName(request)
|
val name = getJobName(request)
|
||||||
val group = getJobGroup(request)
|
val group = getJobGroup(request)
|
||||||
try {
|
try
|
||||||
if (request.createBeforeDelete) {
|
{
|
||||||
|
if (request.createBeforeDelete)
|
||||||
|
{
|
||||||
val response = removeJob(request)
|
val response = removeJob(request)
|
||||||
if (! response.successful) {
|
if (! response.successful)
|
||||||
|
{
|
||||||
throw IllegalArgumentException("Remove job failure " + response.message)
|
throw IllegalArgumentException("Remove job failure " + response.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,28 +30,30 @@ object QuartzEndpoint {
|
|||||||
|
|
||||||
val jobDetail: JobDetail = request.job?.let {
|
val jobDetail: JobDetail = request.job?.let {
|
||||||
JobBuilder.newJob(it::class.java)
|
JobBuilder.newJob(it::class.java)
|
||||||
.withIdentity(name, group)
|
.withIdentity(name, group)
|
||||||
.usingJobData("id", request.jobId)
|
.usingJobData("id", request.jobId)
|
||||||
.build()
|
.build()
|
||||||
} ?: throw IllegalArgumentException("Job is null")
|
} ?: throw IllegalArgumentException("Job is null")
|
||||||
|
|
||||||
val trigger: Trigger = TriggerBuilder.newTrigger()
|
val trigger: Trigger = TriggerBuilder.newTrigger()
|
||||||
.withIdentity("trigger-${request.name}", "trigger-group-${request.group}")
|
.withIdentity("trigger-${request.name}", "trigger-group-${request.group}")
|
||||||
.startNow()
|
.startNow()
|
||||||
.withSchedule(CronScheduleBuilder.cronSchedule(request.expression))
|
.withSchedule(CronScheduleBuilder.cronSchedule(request.expression))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
log.info("Add new job [ {} ] to group [ {} ]", name, group)
|
log.info("Add new job [ {} ] to group [ {} ]", name, group)
|
||||||
scheduler.scheduleJob(jobDetail, trigger)
|
scheduler.scheduleJob(jobDetail, trigger)
|
||||||
|
|
||||||
if (! scheduler.isStarted) {
|
if (! scheduler.isStarted)
|
||||||
|
{
|
||||||
log.info("Scheduler starting")
|
log.info("Scheduler starting")
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
}
|
}
|
||||||
response.successful = true
|
response.successful = true
|
||||||
log.info("Add new job [ {} ] to group [ {} ] successful", name, group)
|
log.info("Add new job [ {} ] to group [ {} ] successful", name, group)
|
||||||
}
|
}
|
||||||
catch (ex: Exception) {
|
catch (ex: Exception)
|
||||||
|
{
|
||||||
log.info("Add new job [ {} ] to group [ {} ] failure ", name, group, ex)
|
log.info("Add new job [ {} ] to group [ {} ] failure ", name, group, ex)
|
||||||
response.successful = false
|
response.successful = false
|
||||||
response.message = ex.message
|
response.message = ex.message
|
||||||
@ -56,11 +62,13 @@ object QuartzEndpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun removeJob(request: SchedulerRequest): SchedulerResponse {
|
fun removeJob(request: SchedulerRequest): SchedulerResponse
|
||||||
|
{
|
||||||
val response = SchedulerResponse()
|
val response = SchedulerResponse()
|
||||||
val name = getJobName(request)
|
val name = getJobName(request)
|
||||||
val group = getJobGroup(request)
|
val group = getJobGroup(request)
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
val scheduler: Scheduler = request.scheduler ?: throw IllegalArgumentException("Scheduler must not null")
|
val scheduler: Scheduler = request.scheduler ?: throw IllegalArgumentException("Scheduler must not null")
|
||||||
|
|
||||||
log.info("Remove job [ {} ] from group [ {} ]", name, group)
|
log.info("Remove job [ {} ] from group [ {} ]", name, group)
|
||||||
@ -68,7 +76,8 @@ object QuartzEndpoint {
|
|||||||
response.successful = true
|
response.successful = true
|
||||||
log.info("Remove job [ {} ] from group [ {} ] successful", name, group)
|
log.info("Remove job [ {} ] from group [ {} ] successful", name, group)
|
||||||
}
|
}
|
||||||
catch (ex: Exception) {
|
catch (ex: Exception)
|
||||||
|
{
|
||||||
log.info("Remove job [ {} ] from group [ {} ] failure ", name, group, ex)
|
log.info("Remove job [ {} ] from group [ {} ] failure ", name, group, ex)
|
||||||
response.successful = false
|
response.successful = false
|
||||||
response.message = ex.message
|
response.message = ex.message
|
||||||
@ -76,11 +85,13 @@ object QuartzEndpoint {
|
|||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getJobName(request: SchedulerRequest): String {
|
private fun getJobName(request: SchedulerRequest): String
|
||||||
|
{
|
||||||
return "job-${request.name}"
|
return "job-${request.name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getJobGroup(request: SchedulerRequest): String {
|
private fun getJobGroup(request: SchedulerRequest): String
|
||||||
|
{
|
||||||
return "job-group-${request.group}"
|
return "job-group-${request.group}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
io.edurt.datacap.scheduler.local.LocalSchedulerPlugin
|
@ -0,0 +1 @@
|
|||||||
|
io.edurt.datacap.scheduler.local.LocalSchedulerService
|
@ -1 +0,0 @@
|
|||||||
io.edurt.datacap.scheduler.local.LocalSchedulerModule
|
|
@ -1,28 +0,0 @@
|
|||||||
package io.edurt.datacap.scheduler.local
|
|
||||||
|
|
||||||
import com.google.inject.Guice
|
|
||||||
import com.google.inject.Injector
|
|
||||||
import com.google.inject.Key
|
|
||||||
import com.google.inject.TypeLiteral
|
|
||||||
import io.edurt.datacap.scheduler.ScheduleManager
|
|
||||||
import io.edurt.datacap.scheduler.Scheduler
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import kotlin.test.assertNotNull
|
|
||||||
|
|
||||||
class LocalSchedulerModuleTest {
|
|
||||||
private val name = "Local"
|
|
||||||
private var injector: Injector? = null
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun before() {
|
|
||||||
injector = Guice.createInjector(ScheduleManager())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test() {
|
|
||||||
val scheduler: Scheduler? = injector?.getInstance(Key.get(object : TypeLiteral<Set<Scheduler?>?>() {}))
|
|
||||||
?.first { v -> v?.name().equals(name) }
|
|
||||||
assertNotNull(scheduler)
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,10 +11,6 @@
|
|||||||
<artifactId>datacap-scheduler-spi</artifactId>
|
<artifactId>datacap-scheduler-spi</artifactId>
|
||||||
<description>DataCap - Scheduler - Spi</description>
|
<description>DataCap - Scheduler - Spi</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<quartz.version>2.3.2</quartz.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
@ -6,7 +6,7 @@ import org.quartz.Job
|
|||||||
@SuppressFBWarnings(value = ["EI_EXPOSE_REP2"])
|
@SuppressFBWarnings(value = ["EI_EXPOSE_REP2"])
|
||||||
data class SchedulerRequest(
|
data class SchedulerRequest(
|
||||||
var name: String? = null,
|
var name: String? = null,
|
||||||
var group: String = "DataCap-Schedule-Group",
|
var group: String = "DataCap-Scheduler-Group",
|
||||||
var expression: String? = null,
|
var expression: String? = null,
|
||||||
var jobId: String? = null,
|
var jobId: String? = null,
|
||||||
var job: Job? = null,
|
var job: Job? = null,
|
||||||
@ -23,7 +23,44 @@ data class SchedulerRequest(
|
|||||||
|
|
||||||
private fun deepCopy(scheduler: org.quartz.Scheduler): org.quartz.Scheduler
|
private fun deepCopy(scheduler: org.quartz.Scheduler): org.quartz.Scheduler
|
||||||
{
|
{
|
||||||
// Implement the deep copy logic of the Scheduler object. The specific implementation depends on the type and structure of the Scheduler.
|
|
||||||
return scheduler
|
return scheduler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object
|
||||||
|
{
|
||||||
|
@JvmStatic
|
||||||
|
fun builder(): Builder
|
||||||
|
{
|
||||||
|
return Builder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder
|
||||||
|
{
|
||||||
|
private var name: String? = null
|
||||||
|
private var group: String = "DataCap-Schedule-Group"
|
||||||
|
private var expression: String? = null
|
||||||
|
private var jobId: String? = null
|
||||||
|
private var job: Job? = null
|
||||||
|
private var scheduler: org.quartz.Scheduler? = null
|
||||||
|
private var createBeforeDelete: Boolean = false
|
||||||
|
|
||||||
|
fun name(name: String?) = apply { this.name = name }
|
||||||
|
fun group(group: String) = apply { this.group = group }
|
||||||
|
fun expression(expression: String?) = apply { this.expression = expression }
|
||||||
|
fun jobId(jobId: String?) = apply { this.jobId = jobId }
|
||||||
|
fun job(job: Job?) = apply { this.job = job }
|
||||||
|
fun scheduler(scheduler: org.quartz.Scheduler?) = apply { this.scheduler = scheduler }
|
||||||
|
fun createBeforeDelete(createBeforeDelete: Boolean) = apply { this.createBeforeDelete = createBeforeDelete }
|
||||||
|
|
||||||
|
fun build() = SchedulerRequest(
|
||||||
|
name = name,
|
||||||
|
group = group,
|
||||||
|
expression = expression,
|
||||||
|
jobId = jobId,
|
||||||
|
job = job,
|
||||||
|
_scheduler = scheduler,
|
||||||
|
createBeforeDelete = createBeforeDelete
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
69
test/datacap-test-scheduler/pom.xml
Normal file
69
test/datacap-test-scheduler/pom.xml
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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>io.edurt.datacap</groupId>
|
||||||
|
<artifactId>datacap</artifactId>
|
||||||
|
<version>2024.4.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>datacap-test-scheduler</artifactId>
|
||||||
|
<description>DataCap - Test - Scheduler</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-reflect</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.edurt.datacap</groupId>
|
||||||
|
<artifactId>datacap-plugin</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.edurt.datacap</groupId>
|
||||||
|
<artifactId>datacap-scheduler-spi</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.edurt.datacap</groupId>
|
||||||
|
<artifactId>datacap-scheduler-local</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<goals>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sourceDirs>
|
||||||
|
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
|
||||||
|
</sourceDirs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -3,8 +3,10 @@ package io.edurt.datacap.scheduler.local
|
|||||||
import io.edurt.datacap.scheduler.SchedulerJob
|
import io.edurt.datacap.scheduler.SchedulerJob
|
||||||
import org.quartz.JobExecutionContext
|
import org.quartz.JobExecutionContext
|
||||||
|
|
||||||
class ExampleJob : SchedulerJob() {
|
class ExampleJob : SchedulerJob()
|
||||||
override fun execute(p0: JobExecutionContext?) {
|
{
|
||||||
|
override fun execute(p0: JobExecutionContext?)
|
||||||
|
{
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package io.edurt.datacap.test.local
|
||||||
|
|
||||||
|
import io.edurt.datacap.plugin.PluginConfigure
|
||||||
|
import io.edurt.datacap.plugin.PluginManager
|
||||||
|
import io.edurt.datacap.plugin.utils.PluginPathUtils
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class LocalSchedulerModuleTest
|
||||||
|
{
|
||||||
|
private val pluginManager: PluginManager
|
||||||
|
private val pluginName = "LocalScheduler"
|
||||||
|
|
||||||
|
init
|
||||||
|
{
|
||||||
|
val projectRoot = PluginPathUtils.findProjectRoot()
|
||||||
|
val config = PluginConfigure.builder()
|
||||||
|
.pluginsDir(projectRoot.resolve("scheduler/datacap-scheduler-local"))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
pluginManager = PluginManager(config).apply { start() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test()
|
||||||
|
{
|
||||||
|
val plugin = pluginManager.getPlugin(pluginName)
|
||||||
|
assertNotNull(plugin.get())
|
||||||
|
}
|
||||||
|
}
|
@ -3,28 +3,34 @@ package io.edurt.datacap.scheduler.local
|
|||||||
import io.edurt.datacap.scheduler.SchedulerRequest
|
import io.edurt.datacap.scheduler.SchedulerRequest
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.quartz.impl.StdSchedulerFactory
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class QuartzEndpointTest {
|
class QuartzEndpointTest
|
||||||
|
{
|
||||||
private val name: String = "TestJob"
|
private val name: String = "TestJob"
|
||||||
private val group: String = "TestGroup"
|
private val group: String = "TestGroup"
|
||||||
private val request = SchedulerRequest()
|
private val request = SchedulerRequest()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun before() {
|
fun before()
|
||||||
|
{
|
||||||
request.name = name
|
request.name = name
|
||||||
request.group = group
|
request.group = group
|
||||||
request.expression = "*/10 * * * * ?"
|
request.expression = "*/10 * * * * ?"
|
||||||
request.job = ExampleJob()
|
request.job = ExampleJob()
|
||||||
|
request.scheduler = StdSchedulerFactory.getDefaultScheduler()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCreateJob() {
|
fun testCreateJob()
|
||||||
|
{
|
||||||
assertTrue(QuartzEndpoint.createJob(request).successful)
|
assertTrue(QuartzEndpoint.createJob(request).successful)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testRemoveJob() {
|
fun testRemoveJob()
|
||||||
|
{
|
||||||
QuartzEndpoint.createJob(request)
|
QuartzEndpoint.createJob(request)
|
||||||
assertTrue(QuartzEndpoint.removeJob(request).successful)
|
assertTrue(QuartzEndpoint.removeJob(request).successful)
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user