Skip to content

Unify the Incremental Execution Loop - #279

Merged
christianhelle merged 6 commits into
mainfrom
prd/2-unify-incremental-loop
Jun 16, 2026
Merged

Unify the Incremental Execution Loop#279
christianhelle merged 6 commits into
mainfrom
prd/2-unify-incremental-loop

Conversation

@christianhelle

@christianhelle christianhelle commented Jun 16, 2026

Copy link
Copy Markdown
Owner

This pull request refactors the incremental HTTP request processing logic to separate core execution from orchestration, enabling both synchronous and asynchronous operation. The main logic for incremental request processing is moved into a new incremental_loop module, which introduces abstractions for sleep (sync/async), supports assertion evaluation, and provides a unified callback-driven control flow. This improves code organization, testability, and future extensibility for async runtimes.

The most important changes are:

Refactoring and Modularization:

  • Extracted the core incremental request processing logic from incremental.rs into a new incremental_loop.rs module, centralizing dependency checks, condition evaluation, variable/function substitution, pre/post delays, and callback handling. ([[1]](https://github.com/christianhelle/httprunner/pull/279/files#diff-c5da75c76b1cb67d92ab6915eb609ac80023231e1c9fa22159da3c11dbdc9347L1-L34), [[2]](https://github.com/christianhelle/httprunner/pull/279/files#diff-ff9970f9790299721cf573c8db0f7f69012719652a12fb27a86800d8fb97359dR1-R365), [[3]](https://github.com/christianhelle/httprunner/pull/279/files#diff-338d60590d00295e243778226a2ca4643c21a3f5ad9cc5696de902b9c844753eR4))

  • Introduced the RequestProcessingResult enum and related types in incremental_loop.rs and re-exported them for use in the rest of the codebase, replacing the previous local definition. ([[1]](https://github.com/christianhelle/httprunner/pull/279/files#diff-c5da75c76b1cb67d92ab6915eb609ac80023231e1c9fa22159da3c11dbdc9347L1-L34), [[2]](https://github.com/christianhelle/httprunner/pull/279/files#diff-ff9970f9790299721cf573c8db0f7f69012719652a12fb27a86800d8fb97359dR1-R365))

Sync/Async Execution and Sleep Abstraction:

  • Added the Sleep trait and its implementations (SyncSleep, AsyncSleep) to abstract over synchronous and asynchronous sleep mechanisms, allowing the processing loop to be used in both blocking and async contexts. ([src/core/src/processor/incremental_loop.rsR1-R365](https://github.com/christianhelle/httprunner/pull/279/files#diff-ff9970f9790299721cf573c8db0f7f69012719652a12fb27a86800d8fb97359dR1-R365))

  • Provided a block_on function for running async code synchronously with a custom no-op waker, enabling the sync orchestration layer to invoke the async processing logic. ([src/core/src/processor/incremental_loop.rsR1-R365](https://github.com/christianhelle/httprunner/pull/279/files#diff-ff9970f9790299721cf573c8db0f7f69012719652a12fb27a86800d8fb97359dR1-R365))

Incremental Processing Improvements:

  • Updated process_http_file_incremental_with_executor in incremental.rs to delegate to the new async processing loop, simplifying the orchestration and ensuring consistent behavior across sync and async modes. ([src/core/src/processor/incremental.rsL56-R56](https://github.com/christianhelle/httprunner/pull/279/files#diff-c5da75c76b1cb67d92ab6915eb609ac80023231e1c9fa22159da3c11dbdc9347L56-R56))

  • Enhanced request execution to support assertion evaluation after request completion, updating the result accordingly. ([src/core/src/processor/incremental_loop.rsR1-R365](https://github.com/christianhelle/httprunner/pull/279/files#diff-ff9970f9790299721cf573c8db0f7f69012719652a12fb27a86800d8fb97359dR1-R365))

These changes lay the groundwork for future async support and improve maintainability by separating orchestration from core logic.

Summary by CodeRabbit

  • Refactor
    • Reorganized request processing logic into a unified module structure to improve code maintainability and consistency across the codebase.

Extract shared incremental loop logic into processor/incremental_loop.rs:
- Sleep trait with SyncSleep and AsyncSleep adapters
- Unified RequestProcessingResult enum
- Deduplicated add_request_context helper
- Generic process_requests_incremental function parameterized by Sleep
- block_on helper for sync path
- NativeSleep future moved from runner/incremental_async.rs
process_http_file_incremental and process_http_file_incremental_with_executor
now delegate to the unified process_requests_incremental via SyncSleep and block_on.
The duplicated loop logic and add_request_context helper are removed.
process_http_requests_incremental_async now delegates to the unified
process_requests_incremental via AsyncSleep. AsyncRequestExecutor,
AsyncRequestFuture, and AsyncRequestProcessingResult are re-exported
from the unified module for backward compatibility.
runner/mod.rs updated to export RequestProcessingResult from processor.
Replace AsyncRequestProcessingResult references with the unified
RequestProcessingResult from httprunner_core::processor. Both types
are now identical; this removes the duplicate enum usage.
@christianhelle christianhelle added enhancement New feature or request Core Core library labels Jun 16, 2026
@christianhelle christianhelle self-assigned this Jun 16, 2026
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@christianhelle, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 45 minutes and 30 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a6b9ca70-50fd-47f2-a2ae-7bd2436e4c4f

📥 Commits

Reviewing files that changed from the base of the PR and between 795d3be and a7d3771.

📒 Files selected for processing (1)
  • src/core/src/processor/incremental_loop.rs
📝 Walkthrough

Walkthrough

A new incremental_loop module centralizes all incremental HTTP request-processing logic (types, sleep abstractions, context tracking, the core async loop, and block_on). The sync incremental.rs and async incremental_async.rs paths become thin wrappers delegating to this shared module. GUI components consuming the result type are updated to use the unified RequestProcessingResult.

Changes

Centralized incremental processing loop

Layer / File(s) Summary
New incremental_loop module: types, sleep, core loop, and block_on
src/core/src/processor/incremental_loop.rs, src/core/src/processor/mod.rs
Introduces AsyncRequestFuture, AsyncRequestExecutor, RequestProcessingResult, the Sleep trait with SyncSleep/AsyncSleep adapters, the thread-based NativeSleep future for non-WASM, add_request_context, the full process_requests_incremental async loop (dependency/condition checks, substitutions, delays, executor invocation, assertion evaluation, context recording, callback-driven break), and a polling block_on helper. mod.rs registers the new submodule as pub(crate).
Sync path refactored to thin wrapper
src/core/src/processor/incremental.rs
process_http_file_incremental_with_executor is rewritten to parse the HTTP file, wrap the executor in an async closure, and call block_on(process_requests_incremental(...)) with SyncSleep. Local RequestProcessingResult definition replaced by pub use re-export from incremental_loop.
Async path refactored to thin wrapper with test updates
src/core/src/runner/incremental_async.rs, src/core/src/runner/mod.rs
process_http_requests_incremental_async delegates to process_requests_incremental with AsyncSleep. Local async types removed and re-exported from incremental_loop. All test callbacks updated from AsyncRequestProcessingResult to RequestProcessingResult variants. block_on simplified to Waker::noop. runner/mod.rs adds pub use RequestProcessingResult.
GUI consumers updated to unified RequestProcessingResult
src/gui/src/results_view.rs, src/gui/src/results_view_async.rs
should_continue_after_async and its tests updated to use RequestProcessingResult (removing wasm-gated AsyncRequestProcessingResult import). map_process_result in results_view_async.rs updated to accept RequestProcessingResult from httprunner_core::processor.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(135, 206, 235, 0.5)
    Note over Caller,callback: process_requests_incremental (sync via block_on / async directly)
  end
  participant Caller
  participant process_requests_incremental
  participant conditions
  participant executor
  participant assertions
  participant callback

  Caller->>process_requests_incremental: requests, executor, Sleep impl, callback
  loop for each HttpRequest
    process_requests_incremental->>conditions: check_dependency(request, contexts)
    process_requests_incremental->>conditions: evaluate_conditions(request, contexts)
    alt dependency/condition not met
      process_requests_incremental->>callback: RequestProcessingResult::Skipped(reason)
    else execution error
      process_requests_incremental->>callback: RequestProcessingResult::Failed(error)
    else
      process_requests_incremental->>executor: execute(request) → HttpResult
      process_requests_incremental->>assertions: evaluate_assertions(result)
      process_requests_incremental->>callback: RequestProcessingResult::Executed(result)
    end
    callback-->>process_requests_incremental: continue: bool
  end
  process_requests_incremental-->>Caller: Result<()>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • christianhelle/httprunner#174: Updates results_view.rs to consume incremental processor Skipped/Executed/Failed outcomes in the GUI flow, directly depending on the same RequestProcessingResult type refactored in this PR.

Poem

🐇 Hop, hop, the loop is shared now,
No more two paths doing the same vow.
SyncSleep, AsyncSleep, one trait to bind,
RequestProcessingResult — one enum to find!
The rabbit tidied the warren with care,
Now sync and async breathe the same air. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is comprehensive and covers the objectives, implementation details, and impact. However, the PR description provided does not follow the template structure with required sections like Type of Change, Testing, Related Issues, and Checklist. Restructure the description to match the template: explicitly state the change type, describe testing performed, link related issues if any, and complete the required checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main refactoring: unifying the incremental execution loop across sync/async paths into a single module.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 prd/2-unify-incremental-loop

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.

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.10256% with 93 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.53%. Comparing base (0629960) to head (a7d3771).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/core/src/processor/incremental_loop.rs 83.15% 93 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #279      +/-   ##
==========================================
+ Coverage   91.12%   92.53%   +1.40%     
==========================================
  Files          67       68       +1     
  Lines        8437     8663     +226     
==========================================
+ Hits         7688     8016     +328     
+ Misses        749      647     -102     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@christianhelle christianhelle changed the title PRD-2: Unify the Incremental Execution Loop Unify the Incremental Execution Loop Jun 16, 2026
Use std::task::Waker::noop() (stabilized in Rust 1.80) instead of
manual NoopWaker implementation in both block_on functions.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/src/processor/incremental_loop.rs`:
- Around line 345-359: The block_on function uses std::task::Waker::noop() which
requires Rust 1.85.0 or later. Either add rust-version = "1.85.0" to the
Cargo.toml file to document the minimum supported Rust version requirement, or
alternatively replace the Waker::noop() call with an implementation-compatible
alternative that works with earlier Rust versions if backward compatibility is
needed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8d807e7-4d52-4623-b21a-4475a04f70c1

📥 Commits

Reviewing files that changed from the base of the PR and between 4629684 and 795d3be.

📒 Files selected for processing (7)
  • src/core/src/processor/incremental.rs
  • src/core/src/processor/incremental_loop.rs
  • src/core/src/processor/mod.rs
  • src/core/src/runner/incremental_async.rs
  • src/core/src/runner/mod.rs
  • src/gui/src/results_view.rs
  • src/gui/src/results_view_async.rs

Comment on lines +345 to +359
/// Block on a future using a no-op waker.
pub(crate) fn block_on<F: Future>(future: F) -> F::Output {
use std::task::{Context, Poll};

let waker = std::task::Waker::noop();
let mut context = Context::from_waker(waker);
let mut future = Box::pin(future);

loop {
match future.as_mut().poll(&mut context) {
Poll::Ready(output) => return output,
Poll::Pending => std::thread::yield_now(),
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What Rust version stabilized std::task::Waker::noop?

💡 Result:

The std::task::Waker::noop method was stabilized in Rust version 1.85.0 [1][2]. The stabilization was implemented via a pull request merged on December 6, 2024, targeting the 1.85.0 milestone [2][3]. Before this, the feature was available as an experimental, nightly-only API [4][5].

Citations:


🏁 Script executed:

# Find and check Cargo.toml for rust-version
fd -n "Cargo.toml$" | head -5 | xargs cat 2>/dev/null | grep -A 5 "rust-version\|edition"

Repository: christianhelle/httprunner

Length of output: 300


🏁 Script executed:

# Search for all uses of Waker::noop in the codebase
rg "Waker::noop" --type rust

Repository: christianhelle/httprunner

Length of output: 241


🏁 Script executed:

# Find and check root Cargo.toml for rust-version
find . -maxdepth 2 -name "Cargo.toml" -type f | head -3 | xargs grep -l "rust-version\|name\|version" 2>/dev/null

Repository: christianhelle/httprunner

Length of output: 82


🏁 Script executed:

# Check the root Cargo.toml specifically
cat Cargo.toml 2>/dev/null | head -20

Repository: christianhelle/httprunner

Length of output: 829


🏁 Script executed:

# Check src/core/Cargo.toml for rust-version
cat src/core/Cargo.toml | grep -A 20 "^\[package\]"

Repository: christianhelle/httprunner

Length of output: 590


🏁 Script executed:

# Check for rust-version files or CI configurations
fd -e "rust-toolchain" -e "rust-toolchain.toml" -e ".rust-version"

Repository: christianhelle/httprunner

Length of output: 51


🏁 Script executed:

# Check CI configurations for minimum Rust version
fd -e "yml" -e "yaml" | xargs grep -l "rust-version\|toolchain" 2>/dev/null | head -5

Repository: christianhelle/httprunner

Length of output: 51


Set MSRV to Rust 1.85.0 to use Waker::noop().

std::task::Waker::noop() requires Rust 1.85.0 or later. Add rust-version = "1.85.0" to Cargo.toml to document this requirement, or remove the use of Waker::noop() if you need to support earlier versions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/src/processor/incremental_loop.rs` around lines 345 - 359, The
block_on function uses std::task::Waker::noop() which requires Rust 1.85.0 or
later. Either add rust-version = "1.85.0" to the Cargo.toml file to document the
minimum supported Rust version requirement, or alternatively replace the
Waker::noop() call with an implementation-compatible alternative that works with
earlier Rust versions if backward compatibility is needed.

17 new unit tests covering:
- SyncSleep trait (zero/nonzero duration)
- block_on helper (ready/future with Pending)
- process_requests_incremental directly (without file parsing):
  empty, single, multiple, callback stops early, inter-request delay,
  dependency skip, condition skip, executor error, assertion failure,
  zero delay, pre-delay, post-delay, index tracking
@christianhelle
christianhelle merged commit d43c005 into main Jun 16, 2026
7 of 8 checks passed
@christianhelle
christianhelle deleted the prd/2-unify-incremental-loop branch June 16, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Core Core library enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant