Sparkdo.Messaging.Scheduling.Scheduler
3.0.0-preview.1
This is a prerelease version of Sparkdo.Messaging.Scheduling.Scheduler.
dotnet add package Sparkdo.Messaging.Scheduling.Scheduler --version 3.0.0-preview.1
NuGet\Install-Package Sparkdo.Messaging.Scheduling.Scheduler -Version 3.0.0-preview.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sparkdo.Messaging.Scheduling.Scheduler" Version="3.0.0-preview.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sparkdo.Messaging.Scheduling.Scheduler" Version="3.0.0-preview.1" />
<PackageReference Include="Sparkdo.Messaging.Scheduling.Scheduler" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sparkdo.Messaging.Scheduling.Scheduler --version 3.0.0-preview.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Sparkdo.Messaging.Scheduling.Scheduler, 3.0.0-preview.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sparkdo.Messaging.Scheduling.Scheduler@3.0.0-preview.1
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sparkdo.Messaging.Scheduling.Scheduler&version=3.0.0-preview.1&prerelease
#tool nuget:?package=Sparkdo.Messaging.Scheduling.Scheduler&version=3.0.0-preview.1&prerelease
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Sparkdo.Messaging.Scheduling.Scheduler
消息的延迟与 Cron 投递:把 Sparkdo.Scheduler 接成 IMessageScheduler 的实现。
到点之后消息原样发布——调度时写一次字节,投递时不再序列化。
| 项 | 值 |
|---|---|
| 包 | Sparkdo.Messaging.Scheduling.Scheduler |
| 交付框架 | net11.0 |
| 依赖 | Sparkdo.Messaging(内核)+ Sparkdo.Scheduler(跨域项目引用);随包还挂 Scheduler 与 Json 两个生成器做分析器 |
| 入口 | AddMessagingScheduling(Action<MessagingSchedulingOptions>?) |
| 消费面 | IMessageScheduler(契约在 Sparkdo.Messaging.Abstractions) |
| AOT / 裁剪 | 兼容 |
接线
builder.Services
.AddSparkdoJson() // 宿主不是可执行文件时也必须调一次
.AddScheduler(options => options.ApplicationName = "orders") // Sparkdo.Scheduler 自己的接线
.AddSparkdoMessaging(
provider => new MessageSerializerRegistry()
.Add(new JsonMessageSerializer(provider.GetRequiredService<IJsonSerializer>())),
bus => bus
.AddTransport(new InMemoryTransport(), TransportDefault.Default)
.RequireScheduler() // 声明:缺调度要在建图时就炸
.AddHandler<OrderPlacedHandler, OrderPlaced>())
.AddMessagingScheduling(options => options.Queue = "messaging")
.AddSparkdoMessagingHosting();
| 两件事不用自己做 | 说明 |
|---|---|
| 登记作业 | ScheduledPublishJob 由 Scheduler 的生成器在程序集加载时登记,不进 DI |
| 写 JSON context | ScheduledPublishArgs 的 context 由本包自带([SparkdoJsonContext])。用户不必为自己的消息类型写 context——消息进调度之前就已经是字节了 |
用法
public sealed class OrderService(IMessageScheduler scheduler)
{
public async ValueTask RemindLater(OrderId id, DateTimeOffset when, CancellationToken ct)
{
var receipt = await scheduler.ScheduleAsync(
new PaymentReminder(id.Value),
ScheduleSpec.At(when), // 或 Delay(TimeSpan) / Cron("每分钟", "* * * * *")
SendOptions.Default,
ct);
if (!receipt.Accepted)
{
// receipt.Reason 是后端给的原文,本包不吞也不改写
throw new InvalidOperationException($"没排上:{receipt.Reason}");
}
_token = receipt.Token; // Occurrence(一次性)或 Schedule(Cron 计划)
}
public ValueTask<bool> Cancel(ScheduleToken token, CancellationToken ct) => scheduler.CancelAsync(token, ct);
}
| 事 | 语义 |
|---|---|
| 谁解析调度面 | 建图期定:RequireScheduler() → 容器注册的 IMessageScheduler → 有 IScheduleBackend 就包成核心的 MessageScheduler → 声明了 NativeSchedule 的传输(今天没有)→ 都没有 |
注入到的 IMessageScheduler |
AddSparkdoMessaging 注册的转发器,取的是图上的那一份。图上没有 → 抛"本图没有调度面",修法直接点名 AddMessagingScheduling() 与 RequireScheduler() |
ScheduleAsync 干了什么 |
查路由、写一次字节、组信封、交给后端。到点用的是这一份字节 |
返回的 Token |
Kind = Occurrence(Delay / At)或 Kind = Schedule(Cron)。CancelAsync 拿它去撤 |
CancelAsync 的 false |
已经执行过、或找不到——不是错误 |
| 到期时刻从哪来 | 宿主登记的 TimeProvider(没登记用 TimeProvider.System)。宿主换了时钟(测试、回放、多节点对表),延迟就跟着那一个"现在"走 |
ScheduleSpec 三种
| 写法 | 落成 Scheduler 的哪个动作 | 约束 |
|---|---|---|
ScheduleSpec.Delay(TimeSpan) |
EnqueueAsync(DueAt = 时钟现在 + 延迟) |
延迟必须 > 0 |
ScheduleSpec.At(DateTimeOffset) |
EnqueueAsync(DueAt = 指定时刻) |
— |
ScheduleSpec.Cron(scheduleName, cron) |
ScheduleCronAsync |
两个参数都不能是空白;凭据指向计划而不是某一次执行 |
ScheduleSpec 是 readonly struct,五个读属性(Kind / DelayDuration / DueAt / ScheduleName /
CronExpression)只有构造它的那个工厂对应的格子有意义。
到点之后发生什么
Scheduler 触发 ScheduledPublishJob
→ 从 args 重建 Envelope(MessageId / 身份 / 内容类型 / 目的地 / Source / Headers)
→ IRawPublisher.PublishRawAsync(body, ...)
→ 走的是与当场发布**同一条**派发管道(中间件一视同仁)
| 后果 | 说法 |
|---|---|
| 载荷是死的 | 排进去之后改消息类型的字段,到点发出的还是当时那份字节。跨这个窗口的兼容要自己管 |
| 中间件照样跑 | 审计、幂等、工作单元都在这条链上——到点发布不是旁路 |
处理器看到的 Source |
调度那一刻写进 ScheduledPublishArgs.Source,与当场发布是同一个表达式。JSON 按名读,所以升级前入队的记录读出来是 null(Version 没升,也不拿目的地址顶上)。把 Source 当必读信息就要把这段窗口算进去 |
选项与失败面
| 选项 / 场景 | 口径 |
|---|---|
MessagingSchedulingOptions.Queue |
null = 用 Scheduler 的默认队列;空串在注册时被 Validate() 拒。它同时作用于 EnqueueOptions.Queue 与 ScheduleOptions.Queue |
SendOptions 任何覆盖项 |
给了就抛:SendOptions 的覆盖项(Identity / MessageId / ContentType / Endpoint / ExpirationTime / Headers)在调度路径上还不生效:到点重发带不过去。修法:先用 SendOptions.Default |
| 停用 Cron 计划 | 不在消息端口里:CancelAsync 收到 Kind = Schedule 的令牌直接抛"停用 Cron 计划('…')不在消息端口里:它要操作者审计。修法:走 Sparkdo.Scheduler 的管理命令(PauseScheduleCommand + 真实 OperatorActor)"。消息端口没有操作者,替它编一个等于伪造审计记录 |
传输声明了 NativeSchedule |
抛"传输 'x' 声明了原生调度(NativeSchedule),但还没有传输实现调度端口" |
| 后端不收 | Accepted = false + Reason 原文带回来;不重试、不改写 |
| 幂等键 | 调度时没设 IdempotencyKey:调度重试的幂等语义要想清楚再定。消息标识本身已可用于接收侧去重(配 Inbox 中间件) |
| Cron 表达式 | 本包不解析,交给 Sparkdo.Crontab(经 Scheduler 域) |
出证
dotnet test src/messaging/test/Sparkdo.Messaging.Scheduling.Scheduler.Tests
三条主用例各自钉一件事(都在假时钟上跑,不真等):
| 用例 | 断言 |
|---|---|
| 延迟投递 | 4 分钟延迟 → 到点前 0 条、+1 分钟恰好 1 条,Token.Kind == Occurrence |
| Cron 投递 | ScheduleSpec.Cron("每分钟", "* * * * *") → 1 条然后 2 条,Token.Kind == Schedule |
| 取消 | 撤掉未执行的排程;撤 Cron 计划那一条断的是拒绝(文案里带"审计") |
另有一条 ScheduledSourceTests 断到点重建的信封 Source / Destination 与当场发布一致。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net11.0 is compatible. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net11.0
- Microsoft.Extensions.ObjectPool (>= 10.0.8)
- Sparkdo.Messaging (>= 3.0.0-preview.1)
- Sparkdo.Scheduler (>= 3.0.0-preview.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-preview.1 | 61 | 10/30/2026 |