Skip to content

Commit a3e6f59

Browse files
authored
feat(scheduler): add QuartZ scheduler module.(for issue #360) (#369)
1 parent 6ded745 commit a3e6f59

15 files changed

Lines changed: 2450 additions & 4 deletions

File tree

agentscope-dependencies-bom/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
<a2a-transport-jsonrpc.version>0.3.3.Final</a2a-transport-jsonrpc.version>
9696
<jedis.version>7.2.0</jedis.version>
9797
<xxl-job.version>3.3.1</xxl-job.version>
98+
<quartz.version>2.3.2</quartz.version>
9899
<spring.version>7.0.2</spring.version>
99100
<spring-boot.version>4.0.1</spring-boot.version>
100101
<nacos-client.version>3.1.1</nacos-client.version>
@@ -319,6 +320,13 @@
319320
<version>${xxl-job.version}</version>
320321
</dependency>
321322

323+
<!-- Quartz Core -->
324+
<dependency>
325+
<groupId>org.quartz-scheduler</groupId>
326+
<artifactId>quartz</artifactId>
327+
<version>${quartz.version}</version>
328+
</dependency>
329+
322330
<!-- Spring WebFlux for AG-UI support -->
323331
<dependency>
324332
<groupId>org.springframework</groupId>

agentscope-distribution/agentscope-all/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@
130130
<optional>true</optional>
131131
</dependency>
132132

133+
<dependency>
134+
<groupId>io.agentscope</groupId>
135+
<artifactId>agentscope-extensions-scheduler-quartz</artifactId>
136+
<scope>compile</scope>
137+
<optional>true</optional>
138+
</dependency>
139+
133140
<dependency>
134141
<groupId>io.agentscope</groupId>
135142
<artifactId>agentscope-extensions-session-mysql</artifactId>

agentscope-distribution/agentscope-bom/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@
185185
<version>${project.version}</version>
186186
</dependency>
187187

188+
<!-- AgentScope Extensions Scheduler Quartz -->
189+
<dependency>
190+
<groupId>io.agentscope</groupId>
191+
<artifactId>agentscope-extensions-scheduler-quartz</artifactId>
192+
<version>${project.version}</version>
193+
</dependency>
194+
188195
<!-- AgentScope Extensions Session MySQL -->
189196
<dependency>
190197
<groupId>io.agentscope</groupId>

agentscope-extensions/agentscope-extensions-scheduler/README.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
The AgentScope Scheduler Extension provides scheduled execution capabilities for Agents, allowing them to run at specified times or intervals. The scheduler module adopts an extensible architecture design that supports multiple scheduling implementations.
66

7-
***Note: The current version only includes the XXL-Job based implementation**, which is suitable for distributed task scheduling.*
7+
*Note: The current version includes implementations based on **XXL-Job** (distributed) and **Quartz** (standalone/clustered).*
88

99
## Key Features
1010

@@ -141,6 +141,55 @@ ScheduleAgentTask task = scheduler.schedule(agentConfig, scheduleConfig);
141141
| View Agent execution logs, which will include event log feedback from each interaction with the model during Agent runtime
142142
![Agent Runtime Logs](images/agent-task-log.png)
143143

144+
### 3. Basic Usage (Quartz Implementation)
145+
146+
**Step 1.** Initialize Quartz Scheduler:
147+
148+
```java
149+
// Create Quartz scheduler instance (with built-in default configuration)
150+
AgentScheduler scheduler = QuartzAgentScheduler.builder()
151+
.autoStart(true)
152+
.build();
153+
```
154+
155+
**Step 2.** Define Agent and Configure Scheduling Strategy:
156+
157+
```java
158+
// 1. Create model configuration
159+
ModelConfig modelConfig = DashScopeModelConfig.builder()
160+
.apiKey(apiKey)
161+
.modelName("qwen-plus")
162+
.build();
163+
164+
// 2. Create Agent configuration
165+
AgentConfig agentConfig = AgentConfig.builder()
166+
.name("MyLocalAgent")
167+
.modelConfig(modelConfig)
168+
.sysPrompt("You are a helpful assistant")
169+
.build();
170+
171+
// 3. Configure scheduling strategy (e.g., execute every 5 seconds)
172+
ScheduleConfig scheduleConfig = ScheduleConfig.builder()
173+
.scheduleMode(ScheduleMode.FIXED_RATE)
174+
.fixedRate(5000L) // 5000ms
175+
.build();
176+
177+
// 4. Register task
178+
ScheduleAgentTask task = scheduler.schedule(agentConfig, scheduleConfig);
179+
```
180+
181+
**Step 3.** Manage Task:
182+
183+
```java
184+
// Pause, resume, cancel
185+
scheduler.pause("MyLocalAgent");
186+
scheduler.resume("MyLocalAgent");
187+
scheduler.cancel("MyLocalAgent");
188+
189+
// Shutdown scheduler
190+
scheduler.shutdown();
191+
```
192+
144193
### Scheduler-Specific Requirements
145194

146195
**For XXL-Job Implementation:**

agentscope-extensions/agentscope-extensions-scheduler/README_zh.md

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
AgentScope 调度器扩展为 Agent 提供定时调度执行功能,允许它们在指定的时间或时间间隔运行。调度器模块采用可扩展的架构设计,支持多种调度实现。
66

7-
*注:**当前版本暂且仅包含基于 XXL-Job 的实现**,适用于分布式任务调度*
7+
*注:当前版本包含基于 **XXL-Job**(分布式)和 **Quartz**(单机/集群)的实现*
88

99
## 核心特性
1010

@@ -43,8 +43,8 @@ AgentScope 调度器扩展为 Agent 提供定时调度执行功能,允许它
4343
┌───────────┼───────────┐
4444
▼ ▼ ▼
4545
┌──────────┐ ┌──────────────┐ ┌──────────┐
46-
│ XXL-Job │ │ Spring Task │ │ Other │
47-
│ ✅ │ │ 🔜 │ │ 🔜 │
46+
│ XXL-Job │ │ Quartz │ │ Other │
47+
│ ✅ │ │ │ │ 🔜 │
4848
└──────────┘ └──────────────┘ └──────────┘
4949
5050
✅ 已实现 🔜 规划中
@@ -140,6 +140,55 @@ ScheduleAgentTask task = scheduler.schedule(agentConfig, scheduleConfig);
140140
| 查看Agent执行日志,其中会包含Agent每一次运行时与模型交互产生的事件日志反馈
141141
![Agent运行日志](images/agent-task-log_zh.png)
142142

143+
### 3. 基本使用(Quartz 实现)
144+
145+
**步骤 1.** 初始化 Quartz 调度器:
146+
147+
```java
148+
// 创建 Quartz 调度器实例(内置默认配置)
149+
AgentScheduler scheduler = QuartzAgentScheduler.builder()
150+
.autoStart(true)
151+
.build();
152+
```
153+
154+
**步骤 2.** 定义 Agent 并配置调度策略:
155+
156+
```java
157+
// 1. 创建模型配置
158+
ModelConfig modelConfig = DashScopeModelConfig.builder()
159+
.apiKey(apiKey)
160+
.modelName("qwen-plus")
161+
.build();
162+
163+
// 2. 创建 Agent 配置
164+
AgentConfig agentConfig = AgentConfig.builder()
165+
.name("MyLocalAgent")
166+
.modelConfig(modelConfig)
167+
.sysPrompt("You are a helpful assistant")
168+
.build();
169+
170+
// 3. 配置调度策略(例如:每5秒执行一次)
171+
ScheduleConfig scheduleConfig = ScheduleConfig.builder()
172+
.scheduleMode(ScheduleMode.FIXED_RATE)
173+
.fixedRate(5000L) // 5000ms
174+
.build();
175+
176+
// 4. 注册任务
177+
ScheduleAgentTask task = scheduler.schedule(agentConfig, scheduleConfig);
178+
```
179+
180+
**步骤 3.** 管理任务:
181+
182+
```java
183+
// 暂停、恢复、取消
184+
scheduler.pause("MyLocalAgent");
185+
scheduler.resume("MyLocalAgent");
186+
scheduler.cancel("MyLocalAgent");
187+
188+
// 关闭调度器
189+
scheduler.shutdown();
190+
```
191+
143192
### 特定调度器实现要求
144193

145194
**对于 XXL-Job 实现:**
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2024-2025 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0"
18+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<modelVersion>4.0.0</modelVersion>
21+
<parent>
22+
<groupId>io.agentscope</groupId>
23+
<artifactId>agentscope-extensions-scheduler</artifactId>
24+
<version>${revision}</version>
25+
<relativePath>../pom.xml</relativePath>
26+
</parent>
27+
28+
<artifactId>agentscope-extensions-scheduler-quartz</artifactId>
29+
<name>AgentScope Java - Extensions - Scheduler - Quartz</name>
30+
<description>Quartz scheduler implementation for AgentScope Java</description>
31+
32+
<properties>
33+
<maven.compiler.source>17</maven.compiler.source>
34+
<maven.compiler.target>17</maven.compiler.target>
35+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
36+
</properties>
37+
<dependencies>
38+
<dependency>
39+
<groupId>io.agentscope</groupId>
40+
<artifactId>agentscope-extensions-scheduler-common</artifactId>
41+
<optional>true</optional>
42+
<scope>provided</scope>
43+
</dependency>
44+
<dependency>
45+
<groupId>org.quartz-scheduler</groupId>
46+
<artifactId>quartz</artifactId>
47+
</dependency>
48+
<dependency>
49+
<groupId>io.agentscope</groupId>
50+
<artifactId>agentscope-core</artifactId>
51+
<optional>true</optional>
52+
<scope>provided</scope>
53+
</dependency>
54+
</dependencies>
55+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2024-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.agentscope.extensions.scheduler.quartz;
17+
18+
import io.agentscope.extensions.scheduler.ScheduleAgentTask;
19+
import io.agentscope.extensions.scheduler.config.ScheduleMode;
20+
import org.quartz.InterruptableJob;
21+
import org.quartz.JobExecutionContext;
22+
import org.quartz.JobExecutionException;
23+
24+
/**
25+
* Quartz Job implementation that executes an AgentScope agent task.
26+
*
27+
* <p>This job retrieves the corresponding {@link QuartzAgentScheduler} and
28+
* {@link QuartzScheduleAgentTask} using job data, and then executes the agent's run logic.
29+
* It also handles the rescheduling for {@code FIXED_DELAY} tasks.
30+
*/
31+
public class AgentQuartzJob implements InterruptableJob {
32+
33+
private volatile boolean interrupted;
34+
35+
/**
36+
* Executes the agent task.
37+
*
38+
* @param context The Quartz JobExecutionContext
39+
* @throws JobExecutionException if the job execution fails
40+
*/
41+
@Override
42+
public void execute(JobExecutionContext context) throws JobExecutionException {
43+
if (interrupted) {
44+
return;
45+
}
46+
String schedulerId = context.getJobDetail().getJobDataMap().getString("schedulerId");
47+
if (schedulerId == null || schedulerId.trim().isEmpty()) {
48+
schedulerId = "default-scheduler";
49+
}
50+
String taskName = context.getJobDetail().getJobDataMap().getString("taskName");
51+
QuartzAgentScheduler scheduler = QuartzAgentSchedulerRegistry.get(schedulerId);
52+
if (scheduler == null) {
53+
return;
54+
}
55+
QuartzScheduleAgentTask task = scheduler.getScheduledAgent(taskName);
56+
if (task == null) {
57+
return;
58+
}
59+
try {
60+
ScheduleAgentTask<io.agentscope.core.message.Msg> t = task;
61+
// Blocking is acceptable here because Quartz jobs run in their own dedicated thread
62+
// pool
63+
// and are executed synchronously; we need to wait for the reactive pipeline to
64+
// complete.
65+
t.run().block();
66+
} catch (Exception e) {
67+
throw new JobExecutionException(e);
68+
}
69+
if (interrupted) {
70+
return;
71+
}
72+
ScheduleMode mode = task.getScheduleConfig().getScheduleMode();
73+
if (mode == ScheduleMode.FIXED_DELAY) {
74+
long delay = context.getJobDetail().getJobDataMap().getLongValue("fixedDelay");
75+
scheduler.rescheduleNextFixedDelay(context.getJobDetail().getKey(), delay);
76+
}
77+
}
78+
79+
/**
80+
* Interrupts the currently running job.
81+
*/
82+
@Override
83+
public void interrupt() {
84+
interrupted = true;
85+
}
86+
}

0 commit comments

Comments
 (0)