Skip to content

Prepare v0.1.3-rc.5 release#34

Merged
vansour merged 5 commits intomainfrom
release/v0.1.3-rc.5
Apr 10, 2026
Merged

Prepare v0.1.3-rc.5 release#34
vansour merged 5 commits intomainfrom
release/v0.1.3-rc.5

Conversation

@vansour
Copy link
Copy Markdown
Owner

@vansour vansour commented Apr 10, 2026

Summary

Prepare v0.1.3-rc.5 for release.

This PR includes the staged maintenance and runtime work that landed during the rc.5 cycle:

  • split state.rs into domain-focused modules while keeping SharedState as the facade
  • slim proxy/mod.rs into an entrypoint and move proxy-specific logic/tests into dedicated modules
  • introduce a unified config transition planner for reload vs restart boundaries
  • add explicit listener hot add/remove support with draining semantics for removed listeners
  • expand characterization and integration coverage for reload, admin snapshot/delta, failover, and listener lifecycle
  • add release-facing and internal docs for reload semantics and runtime architecture
  • update CI and release preflight to use layered fast/slow test entrypoints
  • bump workspace version to 0.1.3-rc.5

Validation

Validated locally with:

  • ./scripts/test-fast.sh
  • ./scripts/test-slow.sh
  • ./scripts/run-tls-gate.sh
  • cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
  • ./scripts/prepare-release.sh --tag v0.1.3-rc.5

Release Notes

  • prerelease branch: release/v0.1.3-rc.5
  • prerelease tag: v0.1.3-rc.5

Copilot AI review requested due to automatic review settings April 10, 2026 03:41
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

Warning

Rate limit exceeded

@vansour has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 46 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 12 minutes and 46 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 8fa15807-ccb5-4786-bb6b-ed32daa981ed

📥 Commits

Reviewing files that changed from the base of the PR and between f3641e6 and 82a88a0.

📒 Files selected for processing (3)
  • crates/rginx-http/src/proxy/tests.rs
  • crates/rginx-runtime/src/bootstrap.rs
  • docs/reload-semantics.md
📝 Walkthrough

Walkthrough

将测试拆分为快速/慢速脚本并在 CI 中串联;重构 rginx-http 的 state 为多个子模块并新增快照/流量/上游统计与 TLS 运行时快照;引入配置转换规划与验证(热重载 vs 重启边界);重构运行时监听器工作组与两阶段重载(prepare/commit);大量测试与文档新增;版本升至 0.1.3-rc.5。

Changes

Cohort / File(s) Summary
CI / Release / Scripts
\.github/workflows/ci.yml, \.github/workflows/release.yml, scripts/test-fast.sh, scripts/test-slow.sh, scripts/prepare-release.sh
将单一 workspace cargo test 拆为 test-fast / test-slow 两阶段脚本并在 CI 串联;添加 tls-gate 作业。
版本与说明文档
Cargo.toml, README.md
包版本上升 0.1.3-rc.40.1.3-rc.5;README 更新测试指令、添加 docs 条目并说明 SIGHUP 重载语义。
State 重构(拆分子模块)
crates/rginx-http/src/lib.rs, crates/rginx-http/src/state.*, crates/rginx-http/src/state/{connections,lifecycle,snapshot_bus,tls_runtime,traffic,upstreams}.rs
将原有大型 state 拆分为多个子模块并保留 SharedState 门面;新增连接 guard、快照总线、TLS 运行时快照、流量/上游统计、生命周期与后台任务管理及相应 API。
配置转换与校验
crates/rginx-http/src/transition.rs, crates/rginx-http/src/lib.rs
新增 transition 模块并对外重导出,定义 ConfigTransitionBoundary/ConfigTransitionPlan,提供 plan_config_transitionvalidate_config_transition(HotReload vs RestartRequired)。
运行时引导与重载工作流
crates/rginx-runtime/src/bootstrap.rs, crates/rginx-runtime/src/reload.rs
引入按监听器的 ListenerWorkerGroup 管理模型,替换扁平 server_tasks;将重载拆为 prepare_reload + commit_reload 两阶段并调整监听器添加/退休/排空逻辑。
代理模块重组与 TLS 错误映射
crates/rginx-http/src/proxy/mod.rs, crates/rginx-http/src/proxy/error_mapping.rs, crates/rginx-http/src/proxy/tests.rs
提取 TLS 错误分类到 error_mapping.rs,将原内联大测试拆出为独立 tests.rsmod.rs 简化为协调/重导出。
监听器 ID 与校验
crates/rginx-config/src/compile/server.rs, crates/rginx-config/src/validate/server.rs, crates/rginx-config/src/validate/tests.rs
监听器 id 从基于索引改为基于规范化 name(listener:{normalized_name});listener 名称归一化改为 ASCII 小写并新增重复名测试。
TLS 运行时快照与 OCSP
crates/rginx-http/src/state/tls_runtime.rs
新增 TLS 运行时快照构造:证书解析/指纹/诊断、OCSP bundle 与运行时合并,并导出 tls_reloadable_fields / tls_restart_required_fields。
流量与上游统计子系统
crates/rginx-http/src/state/traffic.rs, crates/rginx-http/src/state/upstreams.rs, crates/rginx-http/src/state/counters.rs
新增流量/上游统计模块:快照 API、记录函数(请求/响应/GRPC/限流等)、变更标记与同步逻辑;增加 TLS 握手失败细分计数。
应用与测试扩展
crates/rginx-app/src/main.rs, crates/rginx-app/tests/*, crates/rginx-http/src/proxy/tests.rs
print/check 使用 CheckSummary 中的 restart_required_fields;添加/更新大量集成与单元测试(admin、reload、failover、proxy),并引入多个测试辅助函数(延迟服务器、命中计数、可控超时等)。
文档新增
docs/{refactor-plan.md,reload-semantics.md,runtime-architecture.md}
新增重构计划、SIGHUP 重载语义与运行时架构文档,描述重载边界与监听器生命周期。

Sequence Diagram(s)

sequenceDiagram
  participant AdminClient as Admin/API 客户端
  participant Runtime as rginx-runtime
  participant State as SharedState
  participant Bootstrap as Bootstrap/ListenerGroups
  participant Snapshot as SnapshotBus

  AdminClient->>Runtime: 请求 SIGHUP / reload
  Runtime->>State: prepare_reload() (编译、plan_config_transition)
  State-->>Runtime: 返回 PendingReload / 验证结果
  alt 验证通过
    Runtime->>State: commit_reload(next_config)
    State->>State: replace config,准备 retired_listeners,合并 acceptors
    State->>Snapshot: mark_snapshot_changed_components()
    Runtime->>Bootstrap: reconcile_listener_worker_groups()
    Bootstrap->>Bootstrap: retire/add listener groups,start/stop accept loops
    Bootstrap->>State: retire_listener_runtime()/sync_listener_active_connections()
    State->>Snapshot: notify_snapshot_waiters()
    Runtime-->>AdminClient: reload 成功
  else 验证失败
    Runtime-->>AdminClient: reload 拒绝(RestartRequired)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 分钟

Possibly related PRs

Poem

🐰 把大树枝分成许多小巢,
监听器静静学会了来去,
快慢测试并肩跳跃,
重载边界轻声宣布,
新版本跳跃向前跑!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题「Prepare v0.1.3-rc.5 release」准确反映了PR的核心目的,即为v0.1.3-rc.5版本发布做准备。
Description check ✅ Passed PR描述详细阐述了变更内容、验证步骤和发布元数据,与代码变更高度相关,涵盖了state.rs拆分、proxy/mod.rs优化、转换规划器、监听器生命周期管理等核心改动。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/v0.1.3-rc.5

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prepares the v0.1.3-rc.5 release by landing the rc.5-cycle runtime refactors (state/proxy modularization), adding a single-source config transition planner (reload vs restart boundary), enabling explicit listener hot add/remove with draining semantics, and updating CI/release tooling + docs to match.

Changes:

  • Introduce transition planner + validation for reload/restart boundaries and wire it into reload paths.
  • Add listener supervisor-style orchestration in runtime bootstrap (active vs draining listener groups) to support listener add/remove during SIGHUP reload.
  • Split test execution into fast/slow entrypoints and update release preflight + CI workflows; bump version to 0.1.3-rc.5 and add docs.

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
scripts/test-slow.sh New slow-layer test script running integration tests serially.
scripts/test-fast.sh New fast-layer test script running crate-local/unit tests serially.
scripts/prepare-release.sh Switch release preflight from cargo test --workspace to layered fast/slow scripts.
README.md Update version to rc.5; document layered tests and reload/restart boundaries.
docs/runtime-architecture.md New internal architecture doc describing state/proxy/transition/supervisor layers.
docs/reload-semantics.md New reload/restart semantics doc, including listener drain behavior.
docs/refactor-plan.md New refactor plan doc outlining staged maintenance phases.
crates/rginx-runtime/src/reload.rs Split reload into prepare/commit; add transition validation before commit.
crates/rginx-runtime/src/bootstrap.rs Implement active/draining listener worker groups and reload-time listener reconciliation.
crates/rginx-http/src/transition.rs New config transition planner + validation and unit tests.
crates/rginx-http/src/state/upstreams.rs Move upstream stats/snapshot + record hooks into dedicated state module.
crates/rginx-http/src/state/traffic.rs Move traffic counters/snapshots + change tracking into dedicated state module.
crates/rginx-http/src/state/tls_runtime.rs Move TLS runtime snapshot building, OCSP inspection, cert inspection into dedicated module.
crates/rginx-http/src/state/snapshot_bus.rs Move snapshot/version/delta/wait plumbing into dedicated module.
crates/rginx-http/src/state/lifecycle.rs Consolidate reload history, replace/commit, retired listener runtime hooks, background task lifecycle.
crates/rginx-http/src/state/helpers.rs Adjust prepared state construction; remove inline transition validation helper.
crates/rginx-http/src/state/connections.rs Add dedicated connection guards + connection/tls handshake counters integration.
crates/rginx-http/src/proxy/mod.rs Slim proxy entrypoint; extract TLS error mapping and move tests into module.
crates/rginx-http/src/proxy/error_mapping.rs New module for upstream TLS verification labels + TLS failure classification.
crates/rginx-http/src/lib.rs Export transition planner API from the crate root.
crates/rginx-config/src/compile/server.rs Change explicit listener IDs to stable name-derived IDs (listener:<name>).
crates/rginx-app/tests/reload.rs Expand reload integration coverage for listener add/remove + draining semantics.
crates/rginx-app/tests/failover.rs Add coverage ensuring non-idempotent requests don’t fail over on timeout.
crates/rginx-app/tests/check.rs Update expected restart-boundary field labels for explicit listeners.
crates/rginx-app/tests/admin.rs Add admin wait-timeout test; add snapshot/delta coverage for listener lifecycle after reload.
crates/rginx-app/src/main.rs Align check output to use transition boundary summary data.
Cargo.toml Bump workspace version to 0.1.3-rc.5.
Cargo.lock Update lockfile versions to 0.1.3-rc.5.
.github/workflows/release.yml Use layered fast/slow test scripts in release verification.
.github/workflows/ci.yml Split CI tests into fast/slow jobs and add dependency ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/rginx-runtime/src/bootstrap.rs
Comment thread crates/rginx-runtime/src/bootstrap.rs
Comment thread crates/rginx-runtime/src/bootstrap.rs
Comment thread docs/reload-semantics.md Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
crates/rginx-config/src/compile/server.rs (1)

119-131: 统一 listener ID 规范化方式。

规范化后的 listener 名称唯一性已通过 crates/rginx-config/src/validate/server.rs 的验证逻辑得到保障(使用 HashSet 在编译前 fail-fast)。但规范化方式存在不一致:

  • validate/server.rs 使用 to_lowercase()
  • compile/server.rs (line 130) 使用 to_ascii_lowercase()

虽然对 ASCII 输入无实际差异,但应统一为 to_ascii_lowercase() 以保持代码一致性。建议同时补充测试用例覆盖大小写/空白变体的碰撞场景(如 "HTTP""http")。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-config/src/compile/server.rs` around lines 119 - 131, The
listener normalization is inconsistent: compile::explicit_listener_id uses
to_ascii_lowercase() while validation uses to_lowercase(); change the validation
path in validate/server.rs to use to_ascii_lowercase() (the same normalization
used by explicit_listener_id) so IDs match exactly (the validation logic that
builds the HashSet and uniqueness checks should use the same normalized form),
and add a unit test covering collision scenarios (e.g., "HTTP" vs "http" and
variants with surrounding whitespace) to ensure the normalized values collide as
expected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/rginx-app/tests/failover.rs`:
- Around line 31-36: Add an assertion that the first upstream was actually hit
before checking failover behavior: after the request is made in the test that
uses spawn_response_server_with_hits(), assert that
slow_hits.load(Ordering::SeqCst) > 0 and still assert
fast_hits.load(Ordering::SeqCst) == 0 to ensure the request attempted the slow
peer before timing out and not hitting the fast peer; apply the same extra
assertion for the similar test block covering lines 43-56.

In `@crates/rginx-app/tests/reload.rs`:
- Around line 127-135: The test uses a fixed
std::thread::sleep(Duration::from_millis(100)) to assume the background request
reached the draining listener; replace this flaky sleep with an explicit ready
signal: have the background thread (that calls fetch_text_response_with_timeout
or the spawn_delayed_response_server) send a "ready" message over the existing
mpsc::channel (tx) as soon as it has read the request headers or forwarded to
upstream, then in the main test block wait on rx for that ready signal before
calling server.write_config(...) and server.send_signal(libc::SIGHUP); update
fetch_text_response_with_timeout or the delayed server helper to emit the ready
signal at the correct point so the reload happens only after the request is
guaranteed to be in drain.

In `@crates/rginx-http/src/proxy/tests.rs`:
- Line 1915: Remove the hardcoded TEST_SERVER_KEY_PEM constant and instead
generate a temporary key/cert pair at test startup (use the repo's existing
runtime test-certificate generation code/pattern), write them to a tempdir or
return in-memory bytes, and update tests that reference TEST_SERVER_KEY_PEM to
call a helper (e.g., create_test_cert() or get_temp_test_cert()) that returns
the private key and cert paths/bytes; ensure the helper is used by the tests
that previously relied on TEST_SERVER_KEY_PEM so no PEM literals remain in the
source.

In `@crates/rginx-http/src/state/lifecycle.rs`:
- Around line 16-40: status_snapshot currently holds self.inner.read().await
while calling tls_runtime_snapshot_for_config_with_ocsp_statuses (and
mtls_status_snapshot), which does file/OCSP parsing and can block the read lock;
instead, acquire the read lock only long enough to clone the minimal pieces
needed (e.g. state.revision, state.config.clone() or the specific config fields
used, self.config_path.clone(), total counts, and any data needed for
upstream_tls/ocsp lookup like ocsp_statuses via self.ocsp_statuses.read()
clone), drop the lock, then call
tls_runtime_snapshot_for_config_with_ocsp_statuses, mtls_status_snapshot and
upstream_tls_status_snapshots using those cloned values and build the
RuntimeStatusSnapshot; keep references to the functions/fields used:
status_snapshot, self.inner.read().await,
tls_runtime_snapshot_for_config_with_ocsp_statuses, mtls_status_snapshot,
upstream_tls_status_snapshots, and ocsp_statuses so the change is localized.

In `@crates/rginx-http/src/state/snapshot_bus.rs`:
- Around line 184-208: mark_snapshot_changed_components currently increments
snapshot_version and calls snapshot_notify.notify_waiters immediately, which can
wake listeners before callers like record_downstream_request /
record_upstream_request have written entries into traffic_component_versions /
upstream_component_versions; move the notify_waiters call so it runs only after
the target-version maps are updated, or alternatively implement a single helper
that performs "allocate new snapshot_version, update the target map(s)
(traffic_component_versions / upstream_component_versions), then call
snapshot_notify.notify_waiters" atomically and have record_downstream_request
and record_upstream_request use that helper; ensure references to
snapshot_version, snapshot_components.*, traffic_component_versions,
upstream_component_versions and snapshot_notify.notify_waiters are updated
accordingly.

In `@crates/rginx-http/src/state/tls_runtime.rs`:
- Around line 215-222: selected_as_default_for_listeners currently treats a
listener as providing a default cert even when
listener.server.default_certificate points to one of
config.default_vhost.server_names, causing duplicate "default" entries; change
the logic so a listener is only marked in selected_as_default_for_listeners when
listener.server.default_certificate is None (i.e., only when no explicit
default_certificate was configured). Update the branch around
selected_as_default_for_listeners to remove the is_some_and(...) check and only
return vec![listener.name.clone()] when
listener.server.default_certificate.is_none(); keep
build_vhost_certificate_snapshot as-is so the default vhost certificate remains
the authoritative default.

In `@crates/rginx-runtime/src/bootstrap.rs`:
- Around line 79-89: The code calls commit_reload(&state, pending).await before
reconcile_listener_worker_groups(...).await? which makes the new config take
effect even if spawn_listener_worker_group (and other steps in
reconcile_listener_worker_groups) later fail; either move all listener
preparation/validation (the work that can fail in spawn_listener_worker_group
and related helpers) to before calling commit_reload so commit_reload is only
called when those steps are guaranteed to succeed, or add a strong rollback
path: if reconcile_listener_worker_groups returns Err, revert state.http to the
previous config, stop/cleanup any partially started listener groups and worker
tasks started during reconcile_listener_worker_groups, and ensure run() does not
exit in a half-applied state (i.e., perform cleanup/restore instead of
propagating the error with ?). Use the unique symbols commit_reload,
reconcile_listener_worker_groups, spawn_listener_worker_group, state.http and
run to locate where to implement either the pre-commit validation or the
post-commit rollback/cleanup.

In `@docs/reload-semantics.md`:
- Around line 75-76: Links in docs/reload-semantics.md point to absolute local
filesystem paths (/root/github/...), which will break in GitHub/site rendering;
update the two links to use repository-relative relative paths such as
./refactor-plan.md and ./runtime-architecture.md. Locate the markdown list
entries referencing refactor-plan.md and runtime-architecture.md and replace the
hrefs so they read [refactor-plan.md](./refactor-plan.md) and
[runtime-architecture.md](./runtime-architecture.md) (ensure any surrounding
link text remains unchanged).

In `@README.md`:
- Around line 138-158: The README's "热更新边界" section contradicts later examples
and the "配置检查" snippet: update the example and limitation text to match the new
semantics (explicit listeners may be added/removed hot, only listen and
listeners[].listen require restart), remove or modify the old
`reload_requires_restart_for=listen,listeners,...` example and any statements
claiming the entire listener collection requires restart, and ensure references
to `listen`, `listeners[].listen`, `runtime.worker_threads`, and
`runtime.accept_workers` are accurate; also sync the README with
docs/reload-semantics.md and docs/runtime-architecture.md so all three places
state the same restart boundaries.

---

Nitpick comments:
In `@crates/rginx-config/src/compile/server.rs`:
- Around line 119-131: The listener normalization is inconsistent:
compile::explicit_listener_id uses to_ascii_lowercase() while validation uses
to_lowercase(); change the validation path in validate/server.rs to use
to_ascii_lowercase() (the same normalization used by explicit_listener_id) so
IDs match exactly (the validation logic that builds the HashSet and uniqueness
checks should use the same normalized form), and add a unit test covering
collision scenarios (e.g., "HTTP" vs "http" and variants with surrounding
whitespace) to ensure the normalized values collide as expected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 899cc307-0c6f-4e82-bd21-5813ec195b28

📥 Commits

Reviewing files that changed from the base of the PR and between b90d0df and ddd2bdc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • Cargo.toml
  • README.md
  • crates/rginx-app/src/main.rs
  • crates/rginx-app/tests/admin.rs
  • crates/rginx-app/tests/check.rs
  • crates/rginx-app/tests/failover.rs
  • crates/rginx-app/tests/reload.rs
  • crates/rginx-config/src/compile/server.rs
  • crates/rginx-http/src/lib.rs
  • crates/rginx-http/src/proxy/error_mapping.rs
  • crates/rginx-http/src/proxy/mod.rs
  • crates/rginx-http/src/proxy/tests.rs
  • crates/rginx-http/src/state.rs
  • crates/rginx-http/src/state/connections.rs
  • crates/rginx-http/src/state/helpers.rs
  • crates/rginx-http/src/state/lifecycle.rs
  • crates/rginx-http/src/state/snapshot_bus.rs
  • crates/rginx-http/src/state/tls_runtime.rs
  • crates/rginx-http/src/state/traffic.rs
  • crates/rginx-http/src/state/upstreams.rs
  • crates/rginx-http/src/transition.rs
  • crates/rginx-runtime/src/bootstrap.rs
  • crates/rginx-runtime/src/reload.rs
  • docs/refactor-plan.md
  • docs/reload-semantics.md
  • docs/runtime-architecture.md
  • scripts/prepare-release.sh
  • scripts/test-fast.sh
  • scripts/test-slow.sh

Comment thread crates/rginx-app/tests/failover.rs
Comment thread crates/rginx-app/tests/reload.rs
Comment thread crates/rginx-http/src/proxy/tests.rs Outdated
Comment thread crates/rginx-http/src/state/lifecycle.rs
Comment thread crates/rginx-http/src/state/snapshot_bus.rs Outdated
Comment thread crates/rginx-http/src/state/tls_runtime.rs Outdated
Comment thread crates/rginx-runtime/src/bootstrap.rs Outdated
Comment thread docs/reload-semantics.md Outdated
Comment thread README.md
@vansour
Copy link
Copy Markdown
Owner Author

vansour commented Apr 10, 2026

Addressed the actionable automated review comments in commit 3e1cb97.

Handled in this update:

  • tightened failover assertions for slow/fast peer coverage
  • replaced the flaky fixed sleep in the draining-listener reload test with an explicit upstream-ready signal
  • removed hardcoded test server cert/key PEM literals from proxy tests in favor of generated temp identities
  • reduced status_snapshot read-lock scope before TLS/OCSP inspection work
  • fixed snapshot notification ordering so waiters are notified after target-version maps are updated
  • corrected listener default-certificate attribution in TLS runtime snapshots
  • moved explicit listener-name normalization to to_ascii_lowercase() consistently and added coverage
  • changed reload semantics doc links to repository-relative paths
  • pre-created added-listener worker sockets before commit_reload so the reload path does not enter a half-applied state on post-commit listener setup failures
  • synced the README restart-boundary example with the current listeners[].listen semantics

Validation rerun after the fixes:

  • ./scripts/test-fast.sh
  • ./scripts/test-slow.sh
  • targeted rginx-http, rginx-runtime, rginx-config, failover, reload, and admin tests
  • cargo fmt --all --check

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
crates/rginx-http/src/proxy/tests.rs (3)

1659-1795: 考虑提取公共的 ConfigSnapshot 构建逻辑。

snapshot_with_upstreamsnapshot_with_upstreamssnapshot_with_upstream_policysnapshot_with_active_health 函数中 ServerListenerVirtualHost 的构建逻辑大量重复。可以提取一个通用的构建器函数减少重复。

♻️ 可选的重构方案
fn default_server() -> rginx_core::Server {
    rginx_core::Server {
        listen_addr: "127.0.0.1:8080".parse().unwrap(),
        default_certificate: None,
        trusted_proxies: Vec::new(),
        keep_alive: true,
        max_headers: None,
        max_request_body_bytes: None,
        max_connections: None,
        header_read_timeout: None,
        request_body_read_timeout: None,
        response_write_timeout: None,
        access_log_format: None,
        tls: None,
    }
}

fn snapshot_with_upstreams_map(
    upstreams: HashMap<String, Arc<Upstream>>,
) -> rginx_core::ConfigSnapshot {
    let server = default_server();
    rginx_core::ConfigSnapshot {
        runtime: rginx_core::RuntimeSettings {
            shutdown_timeout: Duration::from_secs(1),
            worker_threads: None,
            accept_workers: 1,
        },
        server: server.clone(),
        listeners: vec![rginx_core::Listener {
            id: "default".to_string(),
            name: "default".to_string(),
            server,
            tls_termination_enabled: false,
            proxy_protocol_enabled: false,
        }],
        default_vhost: rginx_core::VirtualHost {
            id: "server".to_string(),
            server_names: Vec::new(),
            routes: Vec::new(),
            tls: None,
        },
        vhosts: Vec::new(),
        upstreams,
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/proxy/tests.rs` around lines 1659 - 1795, The three
snapshot helpers duplicate Server/Listener/VirtualHost construction; extract
helper constructors like default_server(), default_listener(server:
rginx_core::Server) and default_vhost() and a central builder
snapshot_with_upstreams_map(upstreams: HashMap<String, Arc<Upstream>>) that
builds the common Runtime/Server/Listeners/DefaultVhost/vhosts and accepts
upstreams, then refactor snapshot_with_upstream, snapshot_with_upstreams and
snapshot_with_upstream_policy to call these helpers (create Upstream/HashMap as
before, then pass into snapshot_with_upstreams_map) to remove the repeated
Server/Listener/VirtualHost code.

462-558: 建议使用 tempfile crate 管理临时文件。

当前测试在函数末尾手动删除临时文件。如果测试在清理前 panic,临时文件会残留。使用 tempfile::NamedTempFiletempfile::TempDir 可以确保在任何情况下自动清理。

♻️ 建议的改进方案
+use tempfile::TempDir;

 #[test]
 fn proxy_clients_can_select_insecure_and_custom_ca_modes() {
-    let unique = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .expect("system time should be after unix epoch")
-        .as_nanos();
-    let path = std::env::temp_dir().join(format!("rginx-custom-ca-select-{unique}.pem"));
-    std::fs::write(&path, TEST_CA_CERT_PEM).expect("PEM file should be written");
+    let temp_dir = TempDir::new().expect("temp dir should be created");
+    let path = temp_dir.path().join("custom-ca.pem");
+    std::fs::write(&path, TEST_CA_CERT_PEM).expect("PEM file should be written");
     // ... rest of test ...
-    std::fs::remove_file(path).expect("temp PEM file should be removed");
+    // temp_dir 超出作用域时自动清理
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/proxy/tests.rs` around lines 462 - 558, Tests create
temporary PEM files and manually remove them, which can leak files if a test
panics; replace manual file creation/removal with tempfile::NamedTempFile (or
TempDir) in the tests load_custom_ca_store_accepts_pem_files and
proxy_clients_can_select_insecure_and_custom_ca_modes: create a NamedTempFile,
write TEST_CA_CERT_PEM to it, use its path (or persist if necessary) when
calling load_custom_ca_store and when constructing UpstreamTls::CustomCa {
ca_cert_path: ... }, and remove the explicit std::fs::remove_file calls so
cleanup is automatic on drop.

1878-1911: spawn_status_server 缺少优雅关闭机制。

当前实现在无限循环中接受连接,测试完成后线程继续运行。对于长时间运行的测试套件,这可能导致线程资源泄漏。

考虑使用 oneshot channel 或原子标志实现关闭信号:

♻️ 建议的改进方案
+use std::sync::atomic::{AtomicBool, Ordering};

-async fn spawn_status_server(statuses: Arc<Mutex<VecDeque<StatusCode>>>) -> SocketAddr {
+async fn spawn_status_server(
+    statuses: Arc<Mutex<VecDeque<StatusCode>>>,
+) -> (SocketAddr, Arc<AtomicBool>) {
     let listener = TcpListener::bind(("127.0.0.1", 0)).expect("test status listener should bind");
     let listen_addr = listener.local_addr().expect("listener addr should exist");
+    let shutdown = Arc::new(AtomicBool::new(false));
+    let shutdown_clone = shutdown.clone();
+    listener.set_nonblocking(true).expect("set nonblocking should succeed");

     thread::spawn(move || {
-        loop {
-            let Ok((mut stream, _)) = listener.accept() else {
-                break;
-            };
+        while !shutdown_clone.load(Ordering::Relaxed) {
+            match listener.accept() {
+                Ok((mut stream, _)) => { /* handle connection */ }
+                Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
+                    thread::sleep(Duration::from_millis(10));
+                    continue;
+                }
+                Err(_) => break,
+            }
             // ...
         }
     });

-    listen_addr
+    (listen_addr, shutdown)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/proxy/tests.rs` around lines 1878 - 1911,
spawn_status_server currently spawns a background thread that loops forever on
listener.accept, so tests leak threads; change spawn_status_server to accept or
create a shutdown signal (e.g., a tokio::sync::oneshot::Receiver or an
Arc<AtomicBool> flag) and have the spawned thread check that signal inside the
accept loop (or use nonblocking accept/select so the thread can break when
signaled), then close the TcpListener and join the thread; update the function
signature/return to expose the shutdown sender/flag (or a JoinHandle) so callers
can trigger shutdown and await the thread; adjust the inner closures that use
statuses to keep the same behavior while responding to the shutdown signal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/rginx-http/src/state/lifecycle.rs`:
- Around line 214-244: The snapshot mixes two sources: handshake_failures_total
is aggregated from per-listener data (see listener_traffic_counters and the loop
that increments handshake_failures_total), while the handshake_failures_*
category fields are taken from the global counters_snapshot(), causing
inconsistent snapshots after reloads. Fix by making both total and category
fields come from the same source: either (A) compute all handshake_failures_* by
summing per-listener counters inside the same loop that builds
authenticated_connections/authenticated_requests and then set
handshake_failures_total as the sum of those per-listener category sums, or (B)
use the global counters_snapshot() for all handshake_failures_* and set
handshake_failures_total from the same counters (e.g., sum the
handshake_failures_* fields from counters or use a global total if available).
Update the code around MtlsStatusSnapshot construction so
handshake_failures_total and handshake_failures_missing_client_cert / unknown_ca
/ bad_certificate / certificate_revoked / verify_depth_exceeded / other all use
the same counters source.
- Around line 155-172: The reload path leaves newly added/removed
traffic/upstream targets with version 0 (in
build_traffic_component_versions/build_upstream_name_versions) so delta
consumers miss them; fix commit_prepared() so after applying prepared config and
computing next_revision it either (A) assigns next_revision to any newly added
or removed targets (ensure build_* sets target versions to next_revision instead
of 0) or (B) invokes the existing marker helpers to mark per-target changes —
call mark_traffic_targets_changed() for listeners/vhosts/routes and
mark_named_component_target_changed() for upstreams (in addition to the existing
mark_snapshot_changed_components call) so
changed_traffic_targets_since/changed_named_component_targets_since and
ultimately snapshot_delta_since will include those targets.

In `@docs/reload-semantics.md`:
- Line 48: Line 48 contains an awkward phrase "已经进入中的请求"; replace it with a
clearer alternative such as "已经进入处理中的请求" or "已开始处理的请求" (update the sentence
where the phrase "已经进入中的请求" appears in docs/reload-semantics.md to use one of
these alternatives to remove the grammatical error and avoid ambiguity).

---

Nitpick comments:
In `@crates/rginx-http/src/proxy/tests.rs`:
- Around line 1659-1795: The three snapshot helpers duplicate
Server/Listener/VirtualHost construction; extract helper constructors like
default_server(), default_listener(server: rginx_core::Server) and
default_vhost() and a central builder snapshot_with_upstreams_map(upstreams:
HashMap<String, Arc<Upstream>>) that builds the common
Runtime/Server/Listeners/DefaultVhost/vhosts and accepts upstreams, then
refactor snapshot_with_upstream, snapshot_with_upstreams and
snapshot_with_upstream_policy to call these helpers (create Upstream/HashMap as
before, then pass into snapshot_with_upstreams_map) to remove the repeated
Server/Listener/VirtualHost code.
- Around line 462-558: Tests create temporary PEM files and manually remove
them, which can leak files if a test panics; replace manual file
creation/removal with tempfile::NamedTempFile (or TempDir) in the tests
load_custom_ca_store_accepts_pem_files and
proxy_clients_can_select_insecure_and_custom_ca_modes: create a NamedTempFile,
write TEST_CA_CERT_PEM to it, use its path (or persist if necessary) when
calling load_custom_ca_store and when constructing UpstreamTls::CustomCa {
ca_cert_path: ... }, and remove the explicit std::fs::remove_file calls so
cleanup is automatic on drop.
- Around line 1878-1911: spawn_status_server currently spawns a background
thread that loops forever on listener.accept, so tests leak threads; change
spawn_status_server to accept or create a shutdown signal (e.g., a
tokio::sync::oneshot::Receiver or an Arc<AtomicBool> flag) and have the spawned
thread check that signal inside the accept loop (or use nonblocking
accept/select so the thread can break when signaled), then close the TcpListener
and join the thread; update the function signature/return to expose the shutdown
sender/flag (or a JoinHandle) so callers can trigger shutdown and await the
thread; adjust the inner closures that use statuses to keep the same behavior
while responding to the shutdown signal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 7dad8b44-3f37-497d-a369-492899bd7ae6

📥 Commits

Reviewing files that changed from the base of the PR and between ddd2bdc and 3e1cb97.

📒 Files selected for processing (14)
  • README.md
  • crates/rginx-app/tests/failover.rs
  • crates/rginx-app/tests/reload.rs
  • crates/rginx-config/src/validate/server.rs
  • crates/rginx-config/src/validate/tests.rs
  • crates/rginx-http/src/proxy/tests.rs
  • crates/rginx-http/src/state/connections.rs
  • crates/rginx-http/src/state/lifecycle.rs
  • crates/rginx-http/src/state/snapshot_bus.rs
  • crates/rginx-http/src/state/tls_runtime.rs
  • crates/rginx-http/src/state/traffic.rs
  • crates/rginx-http/src/state/upstreams.rs
  • crates/rginx-runtime/src/bootstrap.rs
  • docs/reload-semantics.md
✅ Files skipped from review due to trivial changes (2)
  • crates/rginx-config/src/validate/server.rs
  • crates/rginx-http/src/state/tls_runtime.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • README.md
  • crates/rginx-runtime/src/bootstrap.rs
  • crates/rginx-app/tests/reload.rs

Comment thread crates/rginx-http/src/state/lifecycle.rs
Comment thread crates/rginx-http/src/state/lifecycle.rs Outdated
Comment thread docs/reload-semantics.md Outdated
@vansour
Copy link
Copy Markdown
Owner Author

vansour commented Apr 10, 2026

Follow-up fixes from the latest automated review have been pushed in 00fa88f.

This update includes:

  • consistent mTLS handshake totals/categories from the same listener-scoped source
  • explicit per-target delta version marking for topology changes so listener/upstream add-remove events are visible to delta consumers
  • proactive reload-time listen-address conflict detection before binding newly added listeners
  • repository-relative reload-semantics links and wording cleanup
  • generated temporary test identities in proxy tests instead of hardcoded server cert/key PEM literals
  • stronger test coordination/assertions in failover and reload coverage
  • minor proxy test helper cleanup and temporary-file cleanup improvements

Validation rerun after the update:

  • ./scripts/test-fast.sh
  • ./scripts/test-slow.sh
  • targeted rginx-http, rginx-runtime, rginx-config, failover, reload, and admin tests
  • cargo fmt --all --check

@vansour
Copy link
Copy Markdown
Owner Author

vansour commented Apr 10, 2026

已处理本轮剩余的 AI review 项,并已手动 resolve 对应线程。

本次补充:

  • f3641e6:将 draining listener 的等待从固定 100ms 轮询改为 Notify 驱动,避免长时间 drain 期间周期性 wakeup。
  • f3641e6:补了 prepare_added_listener_bindings() 的回归测试,覆盖 active/draining listener 改名后复用同一 listen_addr 的拒绝路径。
  • 00fa88f / 3e1cb97 中已落地的状态快照、snapshot bus 和文档修复线程也一并收口。

验证:

  • cargo fmt --all --check
  • cargo test -p rginx-runtime --lib -- --test-threads=1
  • ./scripts/test-fast.sh
  • ./scripts/test-slow.sh

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
docs/reload-semantics.md (1)

49-49: 可选:改进表述的自然度。

"新连接最终会变成不可达" 在语义上可以理解,但表述略显生硬。建议改为更自然的表达方式,例如 "该 listener 将不再接受新连接" 或 "新连接将无法建立到该 listener",以提升文档的可读性。

✏️ 可选的改进建议
-- 新连接最终会变成不可达
+- 该 listener 将不再接受新连接

或者:

-- 新连接最终会变成不可达
+- 新连接将无法建立到该 listener
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/reload-semantics.md` at line 49, Replace the awkward phrase
"新连接最终会变成不可达" in docs/reload-semantics.md with a more natural expression; locate
the exact string and change it to one of the suggested alternatives such as "该
listener 将不再接受新连接" or "新连接将无法建立到该 listener" to improve readability while
preserving the original meaning.
crates/rginx-http/src/proxy/tests.rs (2)

506-546: 重复的 Server/ConfigSnapshot 构造建议统一走现有 helper。

这些区块与 Line 1651-1713 的 helper 职责重叠,当前重复较多,后续字段变更会带来高维护成本。建议统一改为 snapshot_with_upstreams(...) / snapshot_with_upstreams_map(...)

♻️ 精简示例
-    let server = rginx_core::Server {
-        listen_addr: "127.0.0.1:8080".parse().unwrap(),
-        default_certificate: None,
-        trusted_proxies: Vec::new(),
-        keep_alive: true,
-        max_headers: None,
-        max_request_body_bytes: None,
-        max_connections: None,
-        header_read_timeout: None,
-        request_body_read_timeout: None,
-        response_write_timeout: None,
-        access_log_format: None,
-        tls: None,
-    };
-    let snapshot = rginx_core::ConfigSnapshot {
-        runtime: rginx_core::RuntimeSettings {
-            shutdown_timeout: std::time::Duration::from_secs(1),
-            worker_threads: None,
-            accept_workers: 1,
-        },
-        server: server.clone(),
-        listeners: vec![rginx_core::Listener {
-            id: "default".to_string(),
-            name: "default".to_string(),
-            server,
-            tls_termination_enabled: false,
-            proxy_protocol_enabled: false,
-        }],
-        default_vhost: rginx_core::VirtualHost {
-            id: "server".to_string(),
-            server_names: Vec::new(),
-            routes: Vec::new(),
-            tls: None,
-        },
-        vhosts: Vec::new(),
-        upstreams: HashMap::from([
-            ("insecure".to_string(), Arc::new(insecure)),
-            ("custom".to_string(), Arc::new(custom)),
-        ]),
-    };
+    let snapshot = snapshot_with_upstreams([
+        ("insecure".to_string(), Arc::new(insecure)),
+        ("custom".to_string(), Arc::new(custom)),
+    ]);

Also applies to: 596-637, 713-754, 796-837, 901-942, 1464-1504

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/proxy/tests.rs` around lines 506 - 546, The test builds
nearly identical rginx_core::Server and rginx_core::ConfigSnapshot structs
inline; replace this duplicated construction with the existing helper functions
snapshot_with_upstreams(...) or snapshot_with_upstreams_map(...) used around
lines ~1651-1713. Update the test to call the appropriate helper and pass the
upstreams (insecure and custom) so Server, RuntimeSettings, Listener,
default_vhost and other shared fields come from the helper instead of being
redefined here; do the same refactor for the other similar blocks (lines noted
in the comment) to remove duplication.

554-560: 临时文件/目录建议统一用 TempDir 托管,避免失败路径遗留。

这里混用了手动删除和 RAII;一旦断言提前失败,Line 644-645 / Line 946-951 的清理不会执行。建议和本文件其它测试保持一致,使用 TempDir 自动清理。

🧹 建议修复
-    let unique = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .expect("system time should be after unix epoch")
-        .as_nanos();
-    let path = std::env::temp_dir().join(format!("rginx-custom-ca-override-{unique}.pem"));
+    let temp_dir = TempDir::new().expect("temp dir should be created");
+    let path = temp_dir.path().join("custom-ca-override.pem");
     std::fs::write(&path, TEST_CA_CERT_PEM).expect("PEM file should be written");
@@
-    std::fs::remove_file(path).expect("temp PEM file should be removed");
+    // TempDir drop 自动清理
-    let unique = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .expect("system time should be after unix epoch")
-        .as_nanos();
-    let dir = std::env::temp_dir().join(format!("rginx-client-identity-cache-{unique}"));
-    std::fs::create_dir_all(&dir).expect("temp dir should be created");
+    let temp_dir = TempDir::new().expect("temp dir should be created");
+    let dir = temp_dir.path().to_path_buf();
@@
-    std::fs::remove_file(first_cert).expect("first cert should be removed");
-    std::fs::remove_file(first_key).expect("first key should be removed");
-    std::fs::remove_file(second_cert).expect("second cert should be removed");
-    std::fs::remove_file(second_key).expect("second key should be removed");
-    std::fs::remove_dir(dir).expect("temp dir should be removed");
+    // TempDir drop 自动清理

Also applies to: 644-645, 844-851, 946-951

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/proxy/tests.rs` around lines 554 - 560, Replace the
manual temp-file creation and manual cleanup with a TempDir so cleanup is
RAII-managed: create a tempfile::TempDir (e.g., let tmp = tempfile::tempdir()?)
and build the PEM path by joining tmp.path() with the filename (instead of using
SystemTime::now() -> unique and std::env::temp_dir()). Write TEST_CA_CERT_PEM to
that path as before, and remove any explicit std::fs::remove_file / manual
deletion code that cleans up path (the cleanup at the earlier referenced lines).
Update all occurrences that use the manual "unique" + std::env::temp_dir()
pattern (the instances creating variable path and writing the PEM in this file)
to use the TempDir-backed path so tests auto-clean on failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/rginx-http/src/proxy/tests.rs`:
- Around line 1806-1823: The spawned detached thread blocks indefinitely on
stream.read(&mut buffer); set read and write timeouts on the TcpStream before
performing I/O (e.g., via stream.set_read_timeout(...) and
stream.set_write_timeout(...)) inside the thread closure, handle timeout or
WouldBlock/TimedOut errors from stream.read and stream.write_all by returning
early (or closing the connection) instead of blocking, and keep the existing
status selection logic (statuses.lock().unwrap_or_else(...), StatusCode usage)
unchanged; ensure flush errors are ignored gracefully after applying the
timeouts.

In `@crates/rginx-runtime/src/bootstrap.rs`:
- Around line 583-587: The test currently binds a temporary socket via
bind_std_listener to get a free port, drops std_listener, then rebinds to the
same listen_addr which creates a race that can yield AddrInUse; instead reuse
the originally bound socket instead of dropping and rebinding—keep std_listener
and pass it directly into whatever API creates the runtime listener (e.g.,
convert the std_listener into the async listener or call the function that
accepts an existing std::net::TcpListener), or change the code paths around
bind_std_listener, std_listener, and listen_addr to call from_std/into_std
variants so the same socket is reused; update both occurrences (the block with
std_listener/listen_addr and the similar block at 606-610) to preserve and reuse
the bound socket rather than dropping then rebinding.
- Around line 419-425: The decrement+notify logic inside the spawned worker is
not panic-safe because it only runs after rginx_http::serve(...).await returns;
create a small Drop-guard inside the async closure (e.g., a local struct Guard
with Drop impl) instantiated before calling rginx_http::serve so that its Drop
always runs on task exit or panic and performs remaining_workers.fetch_sub(1,
Ordering::AcqRel) and, if the result was 1, calls
drain_completion_notify.notify_waiters(); ensure the guard lives for the whole
task lifetime (declare it at top of the closure) and remove or avoid duplicating
the manual decrement after serve returns.

---

Nitpick comments:
In `@crates/rginx-http/src/proxy/tests.rs`:
- Around line 506-546: The test builds nearly identical rginx_core::Server and
rginx_core::ConfigSnapshot structs inline; replace this duplicated construction
with the existing helper functions snapshot_with_upstreams(...) or
snapshot_with_upstreams_map(...) used around lines ~1651-1713. Update the test
to call the appropriate helper and pass the upstreams (insecure and custom) so
Server, RuntimeSettings, Listener, default_vhost and other shared fields come
from the helper instead of being redefined here; do the same refactor for the
other similar blocks (lines noted in the comment) to remove duplication.
- Around line 554-560: Replace the manual temp-file creation and manual cleanup
with a TempDir so cleanup is RAII-managed: create a tempfile::TempDir (e.g., let
tmp = tempfile::tempdir()?) and build the PEM path by joining tmp.path() with
the filename (instead of using SystemTime::now() -> unique and
std::env::temp_dir()). Write TEST_CA_CERT_PEM to that path as before, and remove
any explicit std::fs::remove_file / manual deletion code that cleans up path
(the cleanup at the earlier referenced lines). Update all occurrences that use
the manual "unique" + std::env::temp_dir() pattern (the instances creating
variable path and writing the PEM in this file) to use the TempDir-backed path
so tests auto-clean on failure.

In `@docs/reload-semantics.md`:
- Line 49: Replace the awkward phrase "新连接最终会变成不可达" in docs/reload-semantics.md
with a more natural expression; locate the exact string and change it to one of
the suggested alternatives such as "该 listener 将不再接受新连接" or "新连接将无法建立到该
listener" to improve readability while preserving the original meaning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 02543df6-0a12-4cdc-93f9-d5c7b8e9fd32

📥 Commits

Reviewing files that changed from the base of the PR and between 3e1cb97 and f3641e6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • crates/rginx-http/Cargo.toml
  • crates/rginx-http/src/proxy/tests.rs
  • crates/rginx-http/src/state/connections.rs
  • crates/rginx-http/src/state/counters.rs
  • crates/rginx-http/src/state/lifecycle.rs
  • crates/rginx-http/src/state/traffic.rs
  • crates/rginx-http/src/state/upstreams.rs
  • crates/rginx-runtime/src/bootstrap.rs
  • docs/reload-semantics.md
✅ Files skipped from review due to trivial changes (2)
  • crates/rginx-http/Cargo.toml
  • crates/rginx-http/src/state/connections.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/rginx-http/src/state/upstreams.rs
  • crates/rginx-http/src/state/lifecycle.rs

Comment thread crates/rginx-http/src/proxy/tests.rs
Comment thread crates/rginx-runtime/src/bootstrap.rs Outdated
Comment thread crates/rginx-runtime/src/bootstrap.rs
@vansour
Copy link
Copy Markdown
Owner Author

vansour commented Apr 10, 2026

补一轮收口,已处理并 resolve 最新 AI review。

落地在 82a88a0

  • crates/rginx-runtime/src/bootstrap.rs:worker drain 完成计数改成 Drop guard,保证 task panic/提前退出时仍会递减并通知;测试里复用首次绑定的 socket,去掉“先释放再重绑端口”的竞态。
  • crates/rginx-http/src/proxy/tests.rs:状态服务测试线程补读写超时,避免阻塞 read() 卡死;同时把重复的 snapshot fixture 统一收敛到已有 helper,并把手动临时文件/目录清理改成 TempDir 托管。
  • docs/reload-semantics.md:顺手调整了一处表述。

验证:

  • cargo fmt --all --check
  • cargo test -p rginx-runtime --lib -- --test-threads=1
  • cargo test -p rginx-http --lib -- --test-threads=1
  • ./scripts/test-fast.sh
  • ./scripts/test-slow.sh

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants