Skip to content

[Runtime Configuration] 动态配置 / Hot Reload 长期跟踪 #262

Closed

Description

@SunSi12138

Use case

SharpLink 当前在 dev 分支已经形成比较清晰的 Build/Compile/Materialize 与 immutable runtime snapshot 架构,并且动态模块已经使用 generation、atomic publication 与 drain 等模式解决运行时注册/替换问题。

下一步希望逐步支持 Runtime Dynamic Configuration / Hot Reload:允许部分 Client / Server 运行时策略在实例已经启动后启用、禁用或更新,同时继续保护现有热路径,不把 Builder 阶段的可变 options 直接暴露成长期 mutable runtime state。

本 issue 作为长期总跟踪,不承载各模块的完整实现讨论。具体语义、API、状态迁移和 benchmark 在独立子 issue 中完成。

分析与实施基线:dev。

相关架构背景:#67 已确立 immutable snapshot、单一 ownership、保护热路径、动态 generation/drain 等长期原则;本跟踪在这些原则之上扩展 runtime configuration,而不是重新放开已经冻结的 RuntimeContext / BuildPlan。

总体目标

Builder / Compile
    ↓
建立初始 immutable configuration
    ↓
Client / Server running
    ↓
control path 构造并验证新的 subsystem generation
    ↓
atomic publication
    ↓
新 logical operation 使用新 generation
旧 operation 保持 generation consistency / 必要时 drain

核心目标不是“让所有 Options 都 mutable”,而是把当前“一次 Build 后整个生命周期固定”的 freeze 细化为:

不同 subsystem 拥有各自 immutable generation,并根据语义决定 next-call、next-attempt、next-message、new-session 或 lifecycle-loop 生效。

通用工程原则

  1. 不破坏 Compile / Materialize。 Builder 仍负责构造初始合法状态;动态配置是运行时 control plane,不把 mutable builder options 直接泄漏到 hot path。
  2. Immutable candidate + validate + atomic publish。 更新必须先完整构造候选配置、验证成功,再一次发布;运行时不得观察到半更新状态。
  3. 按 subsystem 分 generation。 不引入一个所有 RPC 都读取的巨型 DynamicRuntimeOptions;Call Policy、Interceptors、Admission、Compression、Session Configuration、Lifecycle Configuration 等应按热路径和语义拆分。
  4. 每个 logical operation 最多 capture 一次相关 generation。 一个 RPC、attempt、stream/session 生命周期内不得混用更新前后的 generation。
  5. 关闭功能必须保留 fast path。 disabled state 优先使用 null / empty immutable snapshot + predictable branch,不使用需要额外虚调用或 allocation 的 no-op runtime object。
  6. 不在 request path 引入全局锁。 更新可以在 control path 加锁、构建、解析和校验;请求路径继续使用 atomic/volatile publication、immutable lookup 与现有无锁/细粒度状态。
  7. Stateful subsystem 必须分离 policy 与 state。 Admission、Circuit Breaker、Endpoint Admission、Rate Limiter 等不能简单 new controller 后替换,否则 active permit、token/window、attempt token 等状态可能失真。
  8. 旧 generation 的资源有明确生命周期。 如果 generation 持有 lease、limiter、timer、partition state 或其他资源,替换后必须有 retire/drain/reclaim 语义;不能在仍有 in-flight operation 时直接 Dispose。
  9. Session / handshake-sensitive 配置不强行即时生效。 会影响 wire negotiation、buffer/table sizing、compression profile、authentication 等配置默认采用 new-session semantics,除非独立设计证明可以安全 renegotiate。
  10. 动态更新不应隐式中断现有业务调用。 降低 concurrency/queue limit 时默认不杀死已经持有 permit 或已经排队的调用,而是限制后续 admission;需要强制取消的行为必须另有显式语义。
  11. 性能变化必须可测。 触及 unary / streaming invocation hot path 的模块必须提交启用、关闭、更新前后的 BenchmarkDotNet 对比,并关注 allocation、吞吐与 p99。
  12. 不在总 issue 锁死公共 API。 本 issue 约束 runtime model 和生效语义;UpdateXxx(...)、control handle、hosting integration 等具体 API 在子 issue 讨论。

Dynamic semantics 分类

分类 典型模块 预期生效点
Next logical call Interceptors、default timeout、retry、exception mapping 下一次 RPC capture 新 snapshot
Next attempt Client Endpoint Admission / Circuit Breaker、Load Balancing 下一次 endpoint attempt
Next message/call policy Compression thresholds 等本地策略 下一次相关 encode/call
Active control loop / next batch RPC flush/batching 现有 send pump 下一次 batching decision
Stateful live update Server Admission、global concurrency、部分 pool policy 保留 runtime state 后更新 policy
Lifecycle/control loop Heartbeat、部分 pool sizing、reconnect policy timer/supervisor loop 接收新 snapshot
New session only Protocol limits、flow-control windows、compression provider/WireProfile、authentication 新连接/新 session
Rolling replacement Transport、listener/TLS topology、service graph root 等资源拓扑 新 generation 建立后排空旧资源

统一 publication 模型

默认模式:

old immutable snapshot / program
            ↓
       control path
            ↓
clone / build candidate
resolve ids / compile route if needed
validate completely
reconcile reusable runtime state
            ↓
      atomic publish
            ↓
new operations capture new generation
old operations keep old generation
            ↓
retire/drain old resource generation when required

禁止的默认模式:

server.Options.Xxx.Value = ...;

多字段配置不得通过逐字段 mutable write 更新,否则无法保证一致性、验证失败回滚和 logical-operation generation consistency。

性能要求

Disabled path

  • 不产生 per-call allocation。
  • 不调用 no-op controller / interceptor pipeline。
  • 不引入 lock。
  • 理想情况下仅增加必要的 snapshot/pointer load + predictable branch;如果某 subsystem 可以完全位于 lifecycle/new-session 路径,则普通 RPC hot path 不应新增任何工作。

Enabled path

  • immutable routing / precompiled execution plan 优先。
  • 同步成功路径不应为了支持动态配置额外分配对象。
  • 只有真实 queue / async wait / contention 才进入较重的状态对象路径。

Update path

  • 可以执行 allocation、validation、dictionary/frozen snapshot 构造和状态 reconciliation。
  • publication 必须短且原子,不阻塞正在运行的 RPC。
  • 更新频率不以 request-rate 为尺度设计;dynamic configuration 属于 control-plane operation。

Stateful subsystem 约束

对 stateful subsystem,默认采用:

Immutable Program / Policy
        +
Reusable Runtime State

例如 Admission:

AdmissionProgram generation N
    ├─ Global rule  ─────┐
    ├─ Contract rule ────┼──> AdmissionState objects
    └─ Method rule ──────┘

update

AdmissionProgram generation N+1
    ├─ unchanged rules -> reuse compatible state
    ├─ resized rules   -> update/reconcile state
    ├─ new rules       -> create state
    └─ removed/structurally changed rules -> retire/drain generation

这样可以避免配置替换时重置 active permit、token bucket/window、breaker state 等真实运行状态。

初始模块清单

下面每一项后续单独建立 issue,并回链本 tracking issue。

  • Dynamic Interceptors

    • Client / Server interceptor immutable pipeline snapshot
    • runtime enable / disable / replace
    • 一个 logical RPC 只 capture 一次 pipeline generation
    • 保留 zero-interceptor direct fast path
    • benchmark disabled / enabled / update cases
  • Dynamic Server Admission Control

    • runtime enable / disable
    • AdmissionProgram 与 runtime admission state 分离
    • dynamic concurrency resize
    • queue policy update
    • token bucket / fixed window / sliding window 的 state-preserving update semantics
    • partition generation / selector replacement
    • retire / drain semantics 与 benchmark
  • Dynamic Client Endpoint Admission / Circuit Breaker

    • policy generation replacement
    • TryAcquire 与 Report 必须绑定同一 policy generation
    • outstanding attempt token / lease 的 retire-drain
    • circuit-breaker state preservation / reset semantics
  • Dynamic Call Policy

    • client default request timeout
    • retry plan / retry policy
    • server exception mapper 等 next-call policy
    • 明确一个 call capture 一次 policy snapshot
  • Dynamic Compression Policy

    • MinimumPayloadBytes
    • MinimumSavingsBytes
    • MinimumSavingsRatio
    • 本地 encode policy 与 wire/session negotiation 分离
    • provider / WireProfile 保持 new-session semantics
  • Dynamic RPC Flush / Batching Policy — [Runtime Configuration][Session] Dynamic RPC flush and batching policy #590

    • FlushSizeThreshold
    • MaxLatency
    • 现有 active Client/Server session 的 send pump 直接采用新策略
    • lowering threshold / latency 时可 prompt wake/re-evaluate
    • 不创建第二 send pump / timer lifecycle
    • 不改变 Protocol v2、flow-control 或 handshake/session invariant
  • Dynamic Lifecycle Configuration

  • Dynamic Telemetry Detail / Enrichment Policy — [Runtime Configuration][Telemetry] Dynamic telemetry detail and enrichment policy #589

    • expensive / high-cardinality tags 与 enrichment
    • optional diagnostic events
    • next-call / next-event semantics
    • sampling/exporter/provider lifecycle 保持 OpenTelemetry / Hosting ownership
  • Dynamic Session Configuration — [Runtime Configuration][Session] Audit session configuration disposition and new-session semantics #588

    • protocol limits
    • receive / connection flow-control windows
    • pending request / stream capacities
    • compression provider profile
    • authentication / handshake-sensitive configuration
    • 明确哪些仅作用于 new session,哪些未来可能支持 renegotiation
  • Runtime Configuration Control Surface / Hosting Integration

    • 在前述模块语义稳定后再统一评估公共 API
    • standalone Client/Server control surface
    • Hosting / OptionsMonitor 等集成是否需要独立 package/API
    • 不为了 API 统一把无关 subsystem 强行合并成一个 runtime options object

建议实施顺序

第一批先覆盖两种最典型的动态模型:

  1. Dynamic Interceptors — 代表纯 immutable snapshot / next-call 动态化。
  2. Dynamic Server Admission Control — 代表 immutable program + stateful runtime state 动态化。

这两个模块稳定后,再将相同 generation / publication / drain 模式复用于其他模块。

随后建议:

  1. Dynamic Call Policy
  2. Dynamic Client Endpoint Admission / Circuit Breaker
  3. Dynamic Compression Policy
  4. Dynamic Lifecycle Configuration
  5. Dynamic RPC Flush / Batching Policy
  6. Dynamic Telemetry Detail / Enrichment Policy
  7. Dynamic Session Configuration
  8. 统一 Runtime Configuration Control Surface / Hosting Integration

测试与验证门禁

每个子 issue 按影响范围至少覆盖:

  • concurrent configuration update + RPC stress;
  • update 与 Stop/Dispose/Drain 并发;
  • in-flight logical operation generation consistency;
  • invalid candidate 不得改变当前已发布配置;
  • repeated enable/disable/update 不得泄漏 resource / task / limiter / lease;
  • fake-time 测试适用于 timer/rate/retry/heartbeat/flush 等时间相关模块;
  • dynamic module / ALC 场景不得因为旧 generation 保留不必要 assembly owner;
  • NativeAOT / trimming 受影响模块继续满足当前约束。

触及 RPC hot path 的子 issue 必须附 BenchmarkDotNet 前后数据:

  • disabled baseline;
  • enabled baseline;
  • steady state after update;
  • allocation / throughput / latency;
  • 不得因为“支持动态配置”在未启用功能时引入明显锁竞争或无依据 allocation。

Compatibility

  • Protocol v2 wire format 默认保持不变。
  • Contract / Method / DTO schema identity 默认保持不变。
  • Dynamic configuration 不自动等于 wire renegotiation。
  • 对 new-session-only 配置,已有 session 保持其 immutable negotiated snapshot,直到自然关闭或显式连接生命周期策略处理。
  • CLR/source API 可以在当前 breaking architecture 收敛阶段按项目策略调整,但不通过大量 compatibility shim 掩盖错误的 runtime model。

Out of scope

本 tracking issue 不直接实现以下内容:

  • 不把所有 RuntimeOptions 改成 thread-safe mutable object。
  • 不要求所有配置都能够即时动态生效。
  • 不为了 hot reload 强行支持现有 session 的 protocol renegotiation。
  • 不在这里决定最终统一 UpdateRuntimeOptions / IOptionsMonitor 等 public API。
  • 不把 Transport / TLS listener / service-provider root 等资源拓扑当成普通 atomic field 修改;需要时采用 generation + rolling replacement 独立设计。
  • 不在一个 PR 中实现所有模块。

总完成定义

  • 所有计划支持动态更新的 subsystem 都有明确的生效点:next-call / next-attempt / lifecycle / active-control-loop / new-session / rolling replacement。
  • 所有模块更新都采用完整 candidate validation + atomic publication,不存在半更新状态。
  • 所有 stateful subsystem 都定义 state preservation / reset / drain 语义。
  • 所有 logical operation 都能证明不会混用两个 configuration generation。
  • disabled feature 保持无 allocation、无 request-path lock,并有 benchmark 证明性能回退处于噪声范围或有明确理由。
  • session-sensitive 配置不会静默改变已协商 session 的 wire/runtime invariant。
  • update 与 stop/dispose/drain/动态模块卸载之间有竞态测试。
  • public control surface 在各模块模型稳定后统一审计,不反向绑死底层实现。
  • 文档明确列出哪些配置支持 runtime update、何时生效、旧 operation/session 如何处理。

Checks

  • 以 dev 为当前分析与实施基线。
  • 已检查现有 open issue,未发现同一 Runtime Dynamic Configuration / Hot Reload 长期跟踪 issue。
  • 本 issue 只建立共同 runtime model、性能约束与模块拆分,不提前锁死具体公共 API。

Activity

  1. SunSi12138 commented on Aug 20, 2026

    @SunSi12138
    OwnerAuthor

    首批两个实施子 issue 已建立:

    后续模块应优先复用这两个 issue 验证后的 publication / generation / lifecycle 模式。

  2. SunSi12138 commented on Aug 21, 2026

    @SunSi12138
    OwnerAuthor

    Progress update: Dynamic Interceptors is complete.

  3. SunSi12138 commented on Aug 22, 2026

    @SunSi12138
    OwnerAuthor

    新增跨模块基础架构跟踪 #273:统一请求资源准入、两阶段 Call Reservation 与 Decode Execution。

    它与本总跟踪的关系是:#262 继续定义 runtime dynamic configuration 的 generation / atomic publication / retire-drain 原则;#273 则提供 Server request hot path 的稳定资源内核,使 call reservation / decode concurrency / retained/decoded bytes / stream budget 不依赖某个动态 policy generation 的存在。

    对 Dynamic Server Admission #264 尤其重要:未来 AdmissionProgram enable/disable/replace 只改变 policy 层,不再决定 compressed Request 是 eager decode 还是 deferred decode。基础 ResourceGovernor safety invariant 在 Admission disabled 时也始终存在。

    #273 还把 compression execution model(inline incremental / cooperative quantum / bounded persistent DecodeExecutor / optional genuine async provider capability)纳入 Phase 0 数据验证,避免为了动态化或安全性把 per-request ThreadPool handoff 固化成长期热路径成本。

  4. SunSi12138 commented on Aug 27, 2026

    @SunSi12138
    OwnerAuthor

    Tracker update — Dynamic Server Admission Control completed (2026-08-27)

    The Dynamic Server Admission Control workstream tracked by #264 is complete and #264 is now closed.

    Final integrated implementation on dev:

    Final #336 exact-head validation: PR Quick 33038771499, CodeQL 33038771343, Padding 33038771236; 1,947/1,947 primary managed tests passed plus NativeAOT/package/load/chaos gates.

    This completes the tracker item for Dynamic Server Admission Control and validates the intended immutable program + stable stateful runtime kernel + atomic publication + retire/drain/reclaim pattern.

    Leaving #262 open for the remaining runtime-configuration workstreams (Dynamic Interceptors, client endpoint admission/circuit breaker, call policy, compression policy, lifecycle/session configuration, and the eventual broader control-surface/hosting integration).

  5. SunSi12138 commented on Sep 5, 2026

    @SunSi12138
    OwnerAuthor

    Housekeeping status — 2026-09-06

    Dynamic Server Admission (#264) has completed its implementation stack and is closed. That removes one major item from this long-term runtime-configuration tracker.

    This tracker remains open because it still owns broader runtime-configuration follow-up areas that are not completed as a whole, including Client endpoint-admission/circuit-breaker dynamics, call-policy updates, compression policy/session-generation updates, lifecycle/session configuration, and the eventual unified control/Hosting surface.

    Treat #264 as completed history; do not reimplement its old phases from this parent body. New work should use current dev and focused leaf issues.

  6. SunSi12138 commented on Sep 6, 2026

    @SunSi12138
    OwnerAuthor

    Status refresh — 2026-09-06

    Current baseline: dev@51e3f2c66a24615abf738f76a2380f223d72f2ab.

    The original tracker defined 8 top-level Runtime Dynamic Configuration workstreams. Re-checking current dev, merged/closed implementation issues, and the remaining open backlog gives this status:

    Completed

    Post-completion simplification work such as #410 does not reopen #264; it may simplify the implementation/semantics further, but the runtime-configuration capability itself is already implemented.

    Related foundations completed, but not a completed #262 workstream

    Remaining top-level workstreams

    • Dynamic Call Policy

    • Dynamic Client Endpoint Admission / Circuit Breaker

    • Dynamic Compression Policy

    • Dynamic Lifecycle Configuration

      • heartbeat interval/timeout;
      • selected connection-pool/lifecycle knobs where live update is actually useful;
      • control-loop/timer rescheduling semantics;
      • update vs reconnect/Stop/Dispose races;
      • no additional ordinary RPC hot-path work.
      • No dedicated implementation leaf is currently established.
    • Dynamic Session Configuration

      • classify protocol limits, flow-control windows, pending/stream capacities, compression provider profile, authentication and other handshake-sensitive state;
      • default to new-session semantics unless a separate design proves safe renegotiation;
      • define rolling replacement / connection-generation behavior where required;
      • prove existing sessions remain internally generation-consistent.
      • No dedicated implementation leaf is currently established.
    • Runtime Configuration Control Surface / Hosting Integration

      • intentionally last;
      • audit the module-specific control APIs after their semantics stabilize;
      • decide whether standalone Client/Server handles and/or Hosting / IOptionsMonitor integration are justified;
      • do not introduce one giant mutable RuntimeOptions object or force unrelated subsystems through one update transaction.
      • No dedicated implementation leaf is currently established.

    Progress

    By top-level workstream count:

    completed: 2 / 8
    remaining: 6 / 8
    

    That is 25% complete / 75% remaining by item count, but item count overstates the remaining engineering effort because #264 Dynamic Server Admission was by far one of the largest and highest-state-space workstreams in the tracker.

    A more useful planning view is:

    Foundation/templates completed
      ✓ immutable next-call publication model (#263)
      ✓ stateful program + stable runtime-state model (#264)
      ✓ common retirement vocabulary (#398)
      ✓ lifetime/TimeBudget semantics (#287)
      ✓ simplified Client attempt terminal/admission coordination (#402)
    
    Still to implement
      1. Dynamic Call Policy
      2. Dynamic Client Endpoint Admission / Circuit Breaker
      3. Dynamic Compression Policy
      4. Dynamic Lifecycle Configuration
      5. Dynamic Session Configuration
      6. Unified control surface / Hosting integration
    

    Recommended continuation order

    Dynamic Call Policy
        ↓
    Dynamic Client Endpoint Admission / Circuit Breaker
        ↓
    Dynamic Compression Policy
        ↓
    Dynamic Lifecycle Configuration
        ↓
    Dynamic Session Configuration
        ↓
    Runtime Configuration Control Surface / Hosting Integration
    

    Call Policy and Client Endpoint Admission can be characterized in parallel because their final generation scopes differ (logical call vs attempt), but implementation should avoid introducing a shared generic configuration framework merely for uniformity.

    Compression should incorporate the final #430 ownership decision before locking a public runtime-update surface. Session-sensitive provider/profile changes should remain new-session-only unless separately proven safe.

    Tracker close condition

    #262 should remain open. It is ready to close only after the six remaining workstreams each have an explicit disposition (implemented, No-Go/not supported dynamically, or intentionally superseded) and the final control-surface/Hosting audit is complete.

  7. SunSi12138 commented on Sep 6, 2026

    @SunSi12138
    OwnerAuthor

    Dynamic Compression Policy 子 issue 已拆出:#550

    最终边界:

    • Provider / WireProfile 保持 Build-time immutable,不做 runtime add/remove/replace;
    • handshake 只协商 session compression capability/profile,不把当前 Enabled 锁死到 session 生命周期;
    • Client / Server 各自拥有 dynamic outbound compression policy(Enabled + adaptive thresholds),next-message 生效;
    • inbound 不设 receive compression policy:raw 直接处理,negotiated compressed frame 自动解压;
    • Client 可通过 negotiated、bounded 的 connection-level control frame 动态表达 Server-outbound compression preference;
    • Client 不得远程控制 Server threshold / compression level / provider,Server 保留最终 CPU/压缩决策权;
    • 不做 active-session WireProfile renegotiation,不做 per-frame 多算法。

    实现/测试/wire capability/benchmark 细节集中在 #550。

  8. SunSi12138 commented on Sep 6, 2026

    @SunSi12138
    OwnerAuthor

    Dynamic Compression Policy 已在 #550 进一步收敛,建议总跟踪按 #550 的最终语义理解,而不再仅视为三个 threshold 的 hot reload:

    • Providers / WireProfile 保持 build-time immutable capability;
    • Client 维护 instance-level Request compression send policy;
    • Server 维护 instance-level Response compression send policy;
    • Client 可通过窄的 response-compression preference wire control 动态表达是否允许/希望 Server 压缩发给自己;
    • remote preference 带 generation + cumulative ACK,支持 reconnect/pool convergence;
    • local policy 是 next-message atomic snapshot,不做 per-session fan-out;
    • 不引入 mutable RuntimeContext compression options、provider replacement 或 active-session profile renegotiation。

    具体并发、ACK/coalescing、handshake initial preference 与性能约束以 #550 为准。Protocol/minor/version bump 不在该子 issue 中决定,留到 2.0 相对 1.1 的发布边界统一处理。

  9. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    Dynamic Compression Policy 已完成落地并回收子 issue:

    最终边界与本 tracking issue 的长期原则一致,但比最初条目进一步收敛:

    • Providers / WireProfile 保持 build-time / handshake capability;
    • Client RequestPolicy 与 Server ResponsePolicy 是独立 instance-scoped immutable runtime snapshot,next-message 生效;
    • SharpLinkCompressionOptions 不再保存 send threshold authority;
    • Client 可通过窄化的 ResponsePreference 控制 Server response direction 是否允许压缩,不能远程修改 Server threshold/provider/level;
    • initial preference 进入 handshake,runtime update 使用 generation + cumulative ACK;
    • fixed cohort、reconnect/Ready publication race、Stop/close/caller cancellation、coalescing 均有明确收敛语义;
    • no-provider / negotiated-disabled / enabled / after-update hot-path evidence 已完成,disabled negotiated path 未观察到额外 allocation,provider attempt 只发生在 enabled 状态;
    • unary / client-streaming / server-streaming / duplex integration、NativeAOT、package gates 已覆盖。

    #550 已按 completed 关闭。#262 继续作为其他 Runtime Configuration 子系统的长期总跟踪。

  10. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    Dynamic Call Policy 已按最终讨论拆成两个独立 Client 全局策略子 issue:

    两者保持独立 publication,不再强制合并成一个巨型 CallPolicy snapshot。现有 method timeout/idempotency、per-call cancellation、Endpoint Admission/Circuit Breaker、session/lifecycle 配置均不纳入这两个 leaf。

  11. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    Dynamic Client Endpoint Admission / Circuit Breaker 已按已确认边界拆成两个独立子 issue:

    两者继续互斥,不在本轮重构 endpoint-cluster / multi-cluster ownership。

  12. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    第三部分(Dynamic Lifecycle Configuration)已按职责拆为两个独立子项:

    两项均保持 #262 的 complete-candidate validation、atomic/control-path publication、Stop/Dispose race safety 与 zero per-RPC lock/allocation 原则。

  13. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    Additional runtime-configuration child tracking:

    These remain separate from #587 Client connection-pool sizing: #587 controls how many outbound connections one Client maintains, while #588/#162 connection admission controls the Server-wide accepted/pre-auth resource envelope.

  14. SunSi12138 commented on Sep 8, 2026

    @SunSi12138
    OwnerAuthor

    Tracker addition — Dynamic Server Call Capacity

    #588 的 Session/pre-session audit 暴露出一个相邻但独立的 runtime-config domain:Server RPC call capacity。

    当前已有两层 build-time hard bound:

    SharpLinkFlowControlOptions.MaxConcurrentCallsPerConnection
    SharpLinkFlowControlOptions.MaxConcurrentCallsPerServer
    

    其中 MaxConcurrentCallsPerServer 是整个 Server 实例的全局 active RPC 上限,MaxConcurrentCallsPerConnection 是单物理连接 active RPC 上限。它们保护的是已经建立 Session 之后、业务 RPC invocation 之前的 call-capacity domain;不属于 #588 的 negotiated Session configuration,也不属于 #162/#588 的 pre-session connection/handshake admission。

    已建立独立实施 issue:#611。

    建议在 #262 roadmap 中将其视为独立的 Dynamic Server Call Capacity 子模块,而不是并入 Dynamic Session Configuration 或 Dynamic Server Admission Control:

    • runtime update MaxConcurrentCallsPerConnection;
    • runtime update MaxConcurrentCallsPerServer;
    • 复用现有 ServerCallAdmission / per-connection active-call accounting,不通过 fresh controller/counter replacement 分裂容量域;
    • multi-field candidate 先完整 validation,再 atomic publication;
    • shrink 采用 non-preemptive semantics:已有 active RPC 不取消,future acquisition 在 usage 高于新 target 时被拒绝/阻塞,usage 自然下降后恢复;
    • increase 对 future acquisition 立即/快速增加容量;
    • update vs acquire/release/cancellation/deadline/connection terminal/Stop 必须线性化;
    • 不因 runtime support 在普通 RPC 路径引入全局锁或无依据 allocation;
    • 与 Dynamic Admission ([Runtime Configuration] Dynamic Server Admission Control:高性能启停、配置更新与状态安全迁移 #264) 保持资源域分离:Admission Global/Contract/Method policy 与基础 Server/per-connection call-capacity hard bound 可以同时存在,一个 RPC 必须满足各自独立的资源约束。

    建议 dynamic-semantics 分类补充为:

    Stateful live update
        -> Server Admission
        -> Server call capacity (per-connection / per-server)
        -> 部分 pool policy
    

    建议后续实施顺序在 Dynamic Server Admission Control 之后增加 Dynamic Server Call Capacity,并把历史 #45 作为 build-time configurability / capacity evidence 的背景,而不是把 #45 已完成的“可配置”误认为已经具备 runtime resize。

    这项不扩大 #588:#588 继续只负责 Session disposition + pre-session connection/handshake target update。

  15. SunSi12138 commented on Sep 9, 2026

    @SunSi12138
    OwnerAuthor

    Runtime Configuration 子项 #611(per-connection / server-wide active RPC hard limits 的运行时 resize)已由 #643 完成并合入 dev,squash SHA e464b4483d74760733af46fe012d148779024be2;#611 已按 completed 关闭。

    该子项采用独立 immutable capacity snapshot + 现有 authoritative active-call accounting:多字段完整校验后原子发布,增长作用于后续 acquisition,缩容不抢占已有调用,Stop/drain 封口更新;未把 hard call capacity 折叠进 Dynamic Admission。Exact-head Fast/Quick/CodeQL/Extended 均通过。

  16. SunSi12138 commented on Sep 10, 2026

    @SunSi12138
    OwnerAuthor

    Final tracker audit — 2026-09-10

    Re-checked the current dev runtime-configuration surface and the work that landed after the 2026-09-06 status refresh. The old 2 / 8 progress comment is now stale: the planned high-value runtime-configuration domains have either been implemented or have an explicit non-live-update disposition.

    Implemented / completed dynamic domains

    The tracker has now produced the following completed work:

    Together these cover the useful runtime semantics originally intended by this tracker:

    next logical call
    next endpoint attempt
    next message
    active control loop / next batch
    stateful live resize
    lifecycle/control loop
    new-session-only disposition
    

    The implementations consistently converged on the intended pattern: complete candidate validation, immutable/current policy publication, stable state where needed, explicit retire/drain/reclaim, and no giant mutable runtime-options object.


    Final audit of possible additional dynamic candidates

    I also re-audited remaining build-time knobs before closing this tracker. None currently justifies extending #262 with another mandatory workstream.

    Server heartbeat interval / peer-liveness timeout — defer / not part of this tracker

    Server still has build-time heartbeat check/timeout configuration, while #586 intentionally implemented the Client side.

    Technically this could be made into another lifecycle/control-loop update. However there is no demonstrated operational requirement strong enough to justify another public runtime mutation surface now, and Server lifecycle ownership is being clarified separately in #646.

    Keep Server heartbeat build-time for now. If a concrete operational use case appears after #646, open a focused Server-heartbeat runtime issue with explicit rescheduling/Stop race semantics rather than reopening this general tracker.

    MinReadyEndpoints / readiness thresholds — defer to lifecycle/readiness model

    These are currently topology/readiness configuration, not a general runtime-options concern. #644 is explicitly separating Client lifecycle from cluster connectivity/readiness, so adding a hot-update API before that model settles would prematurely lock in semantics.

    If runtime readiness-policy changes are still useful after #644, track them as a focused readiness-policy issue. They are not a blocker for #262 completion.

    Connect / handshake / readiness timeout knobs — keep build/new-attempt scoped

    There is no compelling reason to make every connection-establishment timeout independently hot mutable. Their ownership and startup/readiness semantics are also affected by #644/#646.

    Keep them at their current construction/new-attempt boundaries unless a concrete production use case justifies a narrow future issue.

    Server IRpcExceptionMapper replacement — no framework hot-replacement API required

    IRpcExceptionMapper remains an application-provided, instance-scoped object configured at build time. If an application needs policy changes inside its mapper, the mapper itself can own an immutable/application configuration snapshot. SharpLink does not need another framework-level generation/replacement API solely to swap that object.

    This is therefore an explicit No-Go for the current tracker rather than an unfinished Dynamic Call Policy item.

    Protocol / flow-control / pending / stream / compression provider / authentication state — new-session-only by design

    #588 completed the disposition audit. Negotiated or structurally session-scoped state must not silently mutate underneath an active RpcSession. Compression Provider / WireProfile follows the same boundary established by #550.

    No general active-session renegotiation feature is justified.

    ResourceGovernor / decode-memory safety budgets — keep as hard resource configuration unless a real resize use case appears

    #273 established the stable resource-safety kernel. The fact that a hard resource bound is configurable does not automatically mean it should become live-resizable. Runtime shrink/grow would require its own accounting and non-preemption proof similar to #611.

    There is currently no concrete missing operational capability that warrants extending #262 for these bounds.

    Transport / TLS listener / certificate topology / service graph root — rolling replacement, not ordinary hot reload

    These remain resource-topology changes. If a real certificate/listener/transport rolling-rotation use case needs framework support, it should be designed as a focused generation + rolling-replacement feature with explicit ownership and drain semantics, not exposed through a generic mutable runtime-options surface.


    Final control-surface / Hosting disposition

    The final control-surface audit is also a No-Go for one unified mutable runtime configuration object.

    The completed subsystems deliberately have different publication boundaries and state semantics:

    call policy        -> next logical call
    endpoint policy    -> next attempt
    compression        -> next message
    flush              -> active control loop
    pool/capacity      -> stateful reconciliation
    heartbeat/reconnect-> lifecycle loop
    session config     -> new session only
    

    Forcing these through one UpdateRuntimeOptions(...) transaction or one automatically-applied IOptionsMonitor<T> graph would blur ownership, validation, rollback, generation capture and failure reporting.

    The canonical model should therefore remain narrow subsystem-specific runtime control APIs. Applications using Generic Host may bridge their own IOptionsMonitor/configuration source to those explicit APIs when useful. A future optional Hosting adapter can be added only if real repeated application code demonstrates value; it is not required as part of the runtime architecture.


    Relationship to #644 / #646

    #644 and #646 redesign the public Client/Server lifecycle model (StartAsync / WaitForShutdownAsync / StopAsync). They may require existing runtime-control APIs/docs to be adapted to the new lifecycle boundaries, but they do not expose an unfinished #262 dynamic-configuration workstream.

    If those lifecycle changes reveal a genuinely new runtime policy that should be mutable, it should get a focused issue with its own semantics instead of keeping this broad tracker permanently open.


    Closure

    No additional runtime-dynamic feature is currently strong enough to justify extending this long-running tracker.

    The main architectural goal is satisfied:

    SharpLink supports dynamic configuration where runtime mutation has clear operational value and a defensible generation/state model, while explicitly keeping session-sensitive/resource-topology/build-time configuration immutable where hot reload would add more state space than value.

    Closing #262 as completed. Future dynamic-configuration requests should be narrow, use-case-driven issues rather than additions to a permanently open umbrella tracker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions