XiHan.Framework.Scheduling.InMemory
调度的默认实现,同时提供 scheduling.jobs@1(进程内作业存储加抽象包的引擎)与 scheduling.leader@1(进程内租约)。适用于单实例部署、开发与测试;Profiles.Full 已经包含它。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.Scheduling.InMemory |
| 环层 | Ring 3(实现) |
| 能力 | 提供 scheduling.jobs@1、scheduling.leader@1(role: default);依赖 kernel.hosting@1 |
| 特性入口 | InMemorySchedulingFeature(清单 ID xihan.scheduling.inmemory) |
| 配置节 | XiHan:Scheduling(引擎选项)、XiHan:Scheduling:InMemory(MaxRuns) |
| 依赖 | XiHan.Framework.Scheduling.Abstractions;无第三方依赖 |
| AOT | 兼容 |
| 稳定性 | Preview |
概述
本包只有作业存储与领导选举两样东西:misfire、并发阻塞、暂停与恢复、动态登记、重试、取消、历史都由抽象包的 JobSchedulerEngine 完成,语义与数据库实现一致。
InMemoryJobStore 把作业、触发器、运行历史与节点放在进程内的表里,全部操作在一把锁内完成,读出来的是深拷贝,调用方改不到存储里的对象。运行历史有界,最多 MaxRuns 条,超出时丢弃最旧的已结束记录。存储不跨实例共享(IsShared 为假),因此集群唯一的作业(RunOnEveryInstance = false)只在持有领导租约的实例上按计划运行,RunOnEveryInstance 的作业每个实例各自运行。
InMemoryLeaderElection 是进程内的租约表:同一资源在本进程内只有一个持有者,每次获取生成新的持有者标识,过期的记录视为空闲。它不能在实例之间互斥。
特性按能力求解的结果注册契约:
| 被选中的能力 | 注册 |
|---|---|
scheduling.leader | ILeaderElection → InMemoryLeaderElection |
scheduling.jobs | IJobStore → InMemoryJobStore,并装配 JobSchedulerEngine 与 IJobScheduler |
只有 scheduling.leader 被别的 Provider 顶替时(如装配了 Scheduling.Kubernetes),引擎用那个 Provider 的选举,作业存储仍在本进程内。具体类型与健康项总是注册。
何时使用
- 单实例部署、开发环境、测试:零外部基础设施。
- Kubernetes 多副本、只要求集群唯一的作业只跑一份:保留本包,加 Scheduling.Kubernetes 顶替领导选举。
- 需要运行时作业在实例间共享、历史持久化、节点失联恢复:换 Scheduling.Database。
安装与启用
dotnet add package XiHan.Framework.Scheduling.InMemory --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Full 已经装配本包;不用组合包时单独装配:
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Scheduling.InMemory;
var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan.UseFeature<InMemorySchedulingFeature>());配置
| 键 | 类型 | 缺省 | 说明 |
|---|---|---|---|
XiHan:Scheduling:InMemory:MaxRuns | 正整数 | 1000 | 运行历史上限,超出丢弃最旧的已结束记录 |
引擎选项(轮询周期、并发上限、misfire 阈值、租约、历史保留)在 XiHan:Scheduling,见 Scheduling.Abstractions。值不合法时启动抛 ArgumentException。
{
"XiHan": {
"Scheduling": {
"PollIntervalSeconds": 1,
"MaxConcurrentRuns": 32,
"HistoryRetentionDays": 7,
"InMemory": { "MaxRuns": 1000 }
}
}
}主要类型
| 类型 | 说明 |
|---|---|
InMemorySchedulingFeature | 特性:注册存储、选举与健康项,被选中提供作业能力时装配引擎;应用启动时启动引擎,停止时等进行中的运行结束并释放租约 |
InMemoryJobStore | 进程内 IJobStore,IsShared 为假 |
InMemoryLeaderElection | 进程内 ILeaderElection |
InMemorySchedulingOptions | MaxRuns |
InMemorySchedulingHealthContributor | 健康项 scheduling.inmemory.leader(InMemorySchedulingFeature.HealthName) |
使用示例
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Primitives;
using XiHan.Framework.Scheduling.Abstractions;
using XiHan.Framework.Scheduling.Abstractions.Jobs;
using XiHan.Framework.Scheduling.Abstractions.Schedules;
using XiHan.Framework.Scheduling.InMemory;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJob<HeartbeatJob>("heartbeat", JobSchedule.Every(TimeSpan.FromSeconds(10)));
builder.AddXiHan(xihan => xihan.UseFeature<InMemorySchedulingFeature>());
var app = builder.Build();
app.UseXiHan();
app.Run();
public sealed class HeartbeatJob(ILogger<HeartbeatJob> logger) : IJob
{
public ValueTask<Result> RunAsync(JobRun run, InvocationContext context, CancellationToken cancellationToken)
{
logger.LogInformation("Heartbeat run {RunId}.", run.Id);
return ValueTask.FromResult(Result.Success());
}
}framework/samples/KubernetesApp 的 HeartbeatFeature 用同样的写法在特性的 Configure 里登记作业,本地运行时就由本包调度。
行为与限制
- 进程重启后,运行时登记的作业、暂停状态、运行历史都丢失;代码登记的作业在下次启动时重新写入。
- 运行历史全部是运行中的记录、已经没有可丢弃的已结束记录时,开始新运行返回
SCHEDULING_UNAVAILABLE_004。 - 存储不共享,没有节点心跳与失联恢复:
RequestsRecovery不起作用,集群唯一的作业的重试也只有本进程看得到。 - 多个实例各用一份本包时,每个实例都持有自己的进程内租约,集群唯一的作业会在每个实例上各跑一份。
- 健康项
scheduling.inmemory.leader同步计算:引擎在跑为 Ready(进程内租约持有与否都不影响服务),引擎停止为 Stopped;作业能力被别的 Provider 顶替、没有引擎时也是 Ready。 - 通过
Scheduling.Conformance的调度器、存储与领导选举三个套件。
相关
- 调度与后台作业
- Scheduling.Abstractions
- Scheduling.Database
- Scheduling.Kubernetes
- Profiles.Full
- 规范:RFC-0013《调度与领导选举》;ADR-0020
