Sparkdo.Hosting.MicrosoftExtensions 0.0.1-preview.3

This is a prerelease version of Sparkdo.Hosting.MicrosoftExtensions.
dotnet add package Sparkdo.Hosting.MicrosoftExtensions --version 0.0.1-preview.3
                    
NuGet\Install-Package Sparkdo.Hosting.MicrosoftExtensions -Version 0.0.1-preview.3
                    
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.Hosting.MicrosoftExtensions" Version="0.0.1-preview.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sparkdo.Hosting.MicrosoftExtensions" Version="0.0.1-preview.3" />
                    
Directory.Packages.props
<PackageReference Include="Sparkdo.Hosting.MicrosoftExtensions" />
                    
Project file
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.Hosting.MicrosoftExtensions --version 0.0.1-preview.3
                    
#r "nuget: Sparkdo.Hosting.MicrosoftExtensions, 0.0.1-preview.3"
                    
#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.Hosting.MicrosoftExtensions@0.0.1-preview.3
                    
#: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.Hosting.MicrosoftExtensions&version=0.0.1-preview.3&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Sparkdo.Hosting.MicrosoftExtensions&version=0.0.1-preview.3&prerelease
                    
Install as a Cake Tool

Sparkdo.Runtime.Hosting.MicrosoftExtensions

Sparkdo.Runtime.Hosting.MicrosoftExtensions 将 Sparkdo Runtime 接入 .NET Generic Host、Microsoft 依赖注入、IConfiguration、健康检查和 OpenTelemetry。它以 RuntimeHost 为唯一运行时生命周期所有者:启动时完成首次 Catalog 发布,运行中可从配置生成新输入并重协调,关闭时按 Generic Host 的时限执行排空与失败关闭。

这个包适用于常规 .NET 服务、后台进程和控制台应用。它不替 Runtime Core 注入 Microsoft.Extensions.* 依赖;所有框架相关逻辑都位于这一外层适配包。

何时选择此包

场景 推荐入口
已有 IHostApplicationBuilder,首次输入由应用直接提供 IServiceCollection.AddSparkdoRuntime(...)
首次输入与后续更新都来自 IConfiguration 配置驱动的 AddSparkdoRuntime(...)
SecretProvider 输入、初始 Host 绑定或自定义重启处理器 AddSparkdoRuntimeWithConfiguration(...)
单一控制台进程需要处理信号、配置重载和建议退出码 RuntimeConsoleConfigurationHost
不使用 Generic Host 或 Microsoft DI 使用 Sparkdo.Runtime.Hosting

安装

dotnet add package Sparkdo.Runtime.Hosting.MicrosoftExtensions

源代码方式引用时:

<ProjectReference Include="../Sparkdo.Runtime.Hosting.MicrosoftExtensions/Sparkdo.Runtime.Hosting.MicrosoftExtensions.csproj" />

该包会传递引用 Sparkdo.Runtime.Hosting、配置适配层与控制台适配层,以及所需的 Microsoft.Extensions.* 和 OpenTelemetry 抽象包。应用仍须自行提供 IRuntimeRegistrationTable 和运行时输入或输入绑定。

Generic Host 最小接线

下面的组合根适用于输入在应用启动前已经准备好的场景。registrations 必须是应用实际提供的 IRuntimeRegistrationTable

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sparkdo.Runtime;
using Sparkdo.Runtime.Hosting;
using Sparkdo.Runtime.Hosting.MicrosoftExtensions;

var builder = Host.CreateApplicationBuilder(args);

IRuntimeRegistrationTable registrations = GetApplicationRegistrations();
builder.Services.AddSparkdoRuntime(
    registrations,
    options: new RuntimeOptions(),
    initialInputs: CatalogInputs.Empty);

// AddSparkdoRuntime 已登记 RuntimeHost 的 IHostedService;此调用用于显式校验组合顺序。
builder.UseSparkdoRuntime();

using var app = builder.Build();
await app.RunAsync();

GetApplicationRegistrations() 代表应用组合根中的实际注册表提供方式,不是该包提供的 API。AddSparkdoRuntime 已经登记 RuntimeHost 和对应 IHostedServiceUseSparkdoRuntime 是幂等的显式接线点,但必须在 AddSparkdoRuntime 之后调用,否则会抛出 InvalidOperationException

启动后可从容器取得同一实例:

var runtimeHost = app.Services.GetRequiredService<RuntimeHost>();
if (runtimeHost.Status == RuntimeHostStatus.Started && runtimeHost.Runtime is { } runtime)
{
    // 使用 runtime。
}

不要自行创建第二个 RuntimeHost。同一 IServiceCollection 只能注册一个 Sparkdo RuntimeHost,重复注册会抛出 InvalidOperationException

配置驱动的首次输入与重载

配置重载入口把 IConfiguration 与一组 RuntimeConfigurationBinding 连接为首次 CatalogInputs 和后续候选输入:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sparkdo.Runtime;
using Sparkdo.Runtime.Configuration;
using Sparkdo.Runtime.Hosting.MicrosoftExtensions;

static IHost BuildHost(
    string[] args,
    IRuntimeRegistrationTable registrations,
    IEnumerable<RuntimeConfigurationBinding> bindings)
{
    var builder = Host.CreateApplicationBuilder(args);

    builder.Services.AddSparkdoRuntime(
        registrations,
        builder.Configuration,
        bindings,
        options: new RuntimeOptions());
    builder.UseSparkdoRuntime();

    return builder.Build();
}

每个 RuntimeConfigurationBinding 明确描述一个输入路由:RouteKindSchemaSource、配置键 Key、必填性 Required 与来源 Origin。绑定不是按配置树自动发现的;应用应只为已注册 Capability/Input 声明明确、稳定的路由。

当前 Microsoft 配置适配仅接受 json InputKindId。非机密配置值必须是有效 JSON;缺少必填值、重复路由、无效键、超出输入限制或与已注册输入定义不匹配都会使绑定被拒绝。不要把未验证的配置正文写入日志。

机密引用、Host 绑定与重启处理器

需要 SecretProvider 输入或自定义宿主控制时,使用高级入口:

using System.Collections.Immutable;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Sparkdo.Runtime;
using Sparkdo.Runtime.Configuration;
using Sparkdo.Runtime.Configuration.MicrosoftExtensions;
using Sparkdo.Runtime.Hosting;
using Sparkdo.Runtime.Hosting.MicrosoftExtensions;

static void AddConfiguredRuntime(
    IServiceCollection services,
    IRuntimeRegistrationTable registrations,
    IConfiguration configuration,
    IEnumerable<RuntimeConfigurationBinding> bindings,
    HostBindingSnapshot? initialHostBindings,
    IRuntimeHostRestartHandler restartHandler,
    ImmutableArray<RuntimeConfigurationSecretBinding> secretBindings,
    IRuntimeConfigurationSecretReferenceResolver secretReferenceResolver)
{
    var startupOptions = new RuntimeConfigurationHostStartupOptions(
        InitialHostBindings: initialHostBindings,
        RestartHandler: restartHandler,
        SecretBindings: secretBindings,
        SecretReferenceResolver: secretReferenceResolver);

    services.AddSparkdoRuntimeWithConfiguration(
        registrations,
        configuration,
        bindings,
        options: new RuntimeOptions(),
        startupOptions);
}

对于每条 InputSourceScope.SecretProvider 路由,必须提供唯一的 RuntimeConfigurationSecretBinding,并提供 IRuntimeConfigurationSecretReferenceResolver。解析器只能返回目标机密存储中的引用键,不能返回或记录机密正文。同步配置重载不适合 SecretProvider;高级入口会使用可取消的异步解析路径。

InitialHostBindings 会参与首次发布,后续 RuntimeHost 更新会保留已接受的 Host 绑定快照。RestartHandler 用于接收 RuntimeReason 并请求最外层宿主重启;处理器必须实际请求停止或替换进程,不能用无操作实现吞掉重启信号。

Generic Host 生命周期

调用 AddSparkdoRuntime 后,容器中会有:

注册项 作用
RuntimeHost 单例 当前进程唯一的运行时宿主。
IRuntimeRegistrationTable 单例 应用提供的注册表。
IRuntimeHostRestartHandler 使用显式处理器;未提供时使用基于 IHostApplicationLifetime 的默认处理器。
RuntimeHostHostedService 在 Generic Host 启动和停止阶段调用 RuntimeHost
RuntimeConfigurationReloadHostedService 仅配置入口注册;合并配置变更并提交候选 Catalog。
健康检查和 OpenTelemetry 注册 AddSparkdoRuntimeObservability 自动登记。

启动顺序如下:

  1. Generic Host 启动 RuntimeHostHostedService
  2. 服务调用 RuntimeHost.StartAsync,创建 Runtime、创建首次 Catalog 并提交首次重协调。
  3. 只有首次发布成功,Generic Host 才继续正常运行;此时 RuntimeHost.StatusStartedCurrentRevision 非空。
  4. 配置入口在 Runtime 成功首次发布后处理已合并的配置变更,使用当前 CatalogRevision 调用 UpdateCatalogIfCurrentAsync,避免旧配置快照覆盖较新的发布。

首次启动被拒绝时,托管服务会记录结构化原因并抛出 InvalidOperationException,因此 IHost.StartAsyncRunAsync 会失败。异常的 Data 包含 runtime.host.start-resultruntime.reason-code,供最外层启动诊断使用;应用不应依赖文本消息解析原因。

配置重载中的绑定失败、Catalog 拒绝、非成功重协调或宿主不可用会触发失败关闭:Runtime 不再对外可用,并请求 IHostApplicationLifetime.StopApplication()。配置监听器合并高频变更,且启动窗口内到达的变更会在首次发布后处理,不会丢失为一条抢跑更新。

停止与重启

Generic Host 停止时,适配器会从 HostOptions.ShutdownTimeout 中为其他停止参与者预留时间,再调用 RuntimeHost.StopAsync。停止结果不是 RuntimeStopStatus.Stopped、内部停止预算耗尽,或 Generic Host 的关闭令牌先到期时,宿主都会进入失败关闭;不能把该实例重新标记为健康或继续接纳流量。

重协调返回 RestartRequestedQuarantined 时,RuntimeHost 调用 IRuntimeHostRestartHandler。默认处理器会先将 Runtime 失败关闭,再调用 IHostApplicationLifetime.StopApplication()。该调用只请求当前 Host 停止,并不会自行启动新进程;生产部署必须由服务管理器、编排平台或外部监督器根据退出和健康状态创建替换实例。

如果停止请求没有被宿主确认,或重启处理器抛出异常,适配器会执行有界失败关闭并保留失败状态。不要在自定义重启处理器中返回成功后继续让原进程提供服务。

健康检查与 OpenTelemetry

AddSparkdoRuntime 会自动调用 AddSparkdoRuntimeObservability。该方法可安全重复调用;它登记日志、Metrics、OpenTelemetry 源和健康检查,但不配置任何导出器。应用仍应在自己的组合根中配置 OTLP、Prometheus 或其他导出器。

健康检查

两个健康检查按稳定标签注册:

标签常量 标签值 健康含义
RuntimeHostHealthCheckTags.Liveness live FailedStopped 外为健康,表示宿主生命周期仍存活。
RuntimeHostHealthCheckTags.Readiness ready 仅当状态为 StartedRuntime 非空且 CurrentRevision 非空时健康,表示可以接纳业务流量。

应用可以通过 HealthCheckService 按标签执行检查:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Sparkdo.Runtime.Hosting.MicrosoftExtensions;

var healthChecks = app.Services.GetRequiredService<HealthCheckService>();
var readiness = await healthChecks.CheckHealthAsync(
    registration => registration.Tags.Contains(RuntimeHostHealthCheckTags.Readiness),
    cancellationToken);

该包不会替 ASP.NET Core 映射 HTTP 健康检查端点;Web 应用应在自身的 Web 管道中按 liveready 标签映射对应端点。

遥测信号

适配器注册的 ActivitySourceMeter 名称均为 Sparkdo.Runtime.Hosting。生命周期操作会产生:

信号 名称 说明
Activity sparkdo.runtime.host.start 首次启动操作。
Activity sparkdo.runtime.host.stop 停止和排空操作。
Counter sparkdo.runtime.host.operations 生命周期操作计数。
Histogram sparkdo.runtime.host.operation.duration 生命周期操作耗时,单位为秒。
Observable Gauge sparkdo.runtime.host.readiness 就绪状态,1 为就绪,0 为未就绪。

Counter 与 Histogram 使用低基数标签:sparkdo.runtime.operationsparkdo.runtime.outcomesparkdo.runtime.host.status。不要把租户、配置正文、机密引用或高基数输入值附加到这些信号。

控制台与配置一体化宿主

RuntimeConsoleConfigurationHost 适合不使用 Generic Host、但需要同一控制台进程处理配置首次绑定、配置重载、信号、停止与建议退出码的程序:

using Microsoft.Extensions.Configuration;
using Sparkdo.Runtime;
using Sparkdo.Runtime.Configuration;
using Sparkdo.Runtime.Hosting.MicrosoftExtensions;

static async Task<int> RunConsoleAsync(
    IRuntimeRegistrationTable registrations,
    IConfiguration configuration,
    IEnumerable<RuntimeConfigurationBinding> bindings,
    CancellationToken cancellationToken)
{
    await using var host = new RuntimeConsoleConfigurationHost(
        registrations,
        configuration,
        bindings,
        new RuntimeConsoleConfigurationHostOptions(
            RuntimeOptions: new RuntimeOptions(),
            ShutdownTimeout: TimeSpan.FromSeconds(30)));

    var result = await host.RunWithResultAsync(cancellationToken);
    return result.SuggestedExitCode;
}

该类型不会直接调用 Environment.Exit;调用方负责把 ConsoleRuntimeRunResult.SuggestedExitCode 交给进程入口。配置重载要求 HostRestart 时,结果保留建议退出码 75;调用方取消的正常终止建议为 0;不可恢复的宿主或配置失败建议为 1。控制台宿主在成功首次发布后才处理已合并的配置变更,并在处置时为重载工作和控制台停止共享一个总关闭预算。

RuntimeConsoleConfigurationHostOptions 还提供 InitialHostBindingsStopOptionsSecretBindingsSecretReferenceResolverLogger。机密输入的约束与 Generic Host 高级配置入口相同。

依赖与边界

该包负责把 Runtime 接入 Microsoft 生态,但不负责:

  • 生成或维护应用的 IRuntimeRegistrationTable
  • 定义业务 Capability、输入路由、Schema 或配置来源身份;
  • 选择并配置 OpenTelemetry 导出器;
  • 映射 Web 健康检查端点;
  • 自行拉起新的进程或实现部署平台的重启策略。

将这些决策保留在应用组合根和部署层,可使 Runtime 的更新、健康状态与外部监督器行为保持一致。

验证

在仓库根目录执行:

dotnet build src/runtime/src/Sparkdo.Runtime.Hosting.MicrosoftExtensions/Sparkdo.Runtime.Hosting.MicrosoftExtensions.csproj --configuration Release
dotnet test src/runtime/test/Sparkdo.Runtime.Specification.Tests/Sparkdo.Runtime.Specification.Tests.csproj --configuration Release --filter "FullyQualifiedName~RuntimeHostingAdapterTests"

测试覆盖 Generic Host 启停、启动拒绝传播、配置首次绑定与重载、重启退出码、关闭预算、健康检查与 OpenTelemetry 生命周期信号。

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.0.1-preview.3 44 8/26/2026
0.0.1-preview.2 53 8/25/2026
0.0.1-preview.1 55 8/25/2026