Potential File Structure for Complex Dynamic Workloads with Separation of Concerns, Weighted Scenarios & Conditional Execution #910
Replies: 4 comments 1 reply
-
|
Hi @CMorrisonJHA |
Beta Was this translation helpful? Give feedback.
-
|
You are right to be concerned about potential blocking in the RequestClient. In my Visual Studio solution I have coded such a RequestClient and placed it in yet another class (following the separation of concerns principle). I did not post this class above. But it would look something like what is below. The example below follows Microsoft's recommendations to use a static/singleton HttpClient with a correctly configured SocketsHttpHandler with Polly resilience (timeout + circuit‑breaker + bulkhead), and automatic re‑creation of the client when a fault threshold is hit. Micorosoft's guidance is a starting place for a non-blocking client. Let me know if you feel I am on the wrong track with this. (Is there something else in NBomber or in my file structure which would block? The data sources?) Static HttpClient with resilience Plus Other Features References
The above is an illustration of a fault-tolerant HTTPClient, that I WOULD build if I was using REST or HTTP calls. I should note that I have not actually implemented the above code (but I have implemented clients like it.) Note that for actual load testing use, we usually don't want to retry.: if a request fails because the system under test has a problem, we want to mark that request as an failure of the system under test. But we DO want to "retry" if the client lifetime expired (e.g., in endurance tests), and we also want to get a new client AFTER the client has faulted (so that we can continue with the test). Automatic retries in load testing can mask true SUT (system under test) failures and inflate perceived throughput/latency. We do want the client to recover and keep sending load after a failure—e.g., by re‑creating the HttpClient when there’s evidence of systemic faults (timeouts, repeated 5xx, connection errors). For better or worse, the current system I'm testing uses WCF (Microsoft SOAP, XML requests). For this project, I have implemented a very similar fault tolerant client (with a client pool) except it is for WCF and uses WCF channel factories. I would be glad to post that here as well, but it's 350 lines long . .. . My WCF client uses a pool of WCF channels. Each channel is returned to the pool after its lifetime. If a channel gets faulted, the request automatically gets another channel from the pool. If you still feel that there might be blocking due to NBomber internal architecture, or something else I might have wrong, please let me know. I actually have not yet tested my WCF client at very high volume. My high volume test will start at 800 threads, and ramp up to about 2500 threads. It is a capacity test that is designed to knock over my Production system, so in my client I anticipate that there's going to be http 500's, timeouts, channel faults, etc. |
Beta Was this translation helpful? Give feedback.
-
|
Note that it might be cleaner and shorter to write the HTTP client using Dependency Injection: Client In test Method Polly is open-source, NuGet-based, and endorsed by Microsoft because it makes resilience easy, composable, and production-ready for .NET apps. It's shorter because IHttpClientFactory and the DI container hide a lot of the boilerplate (client creation, handler pooling/rotation, disposal, and policy wiring). With DI, you declaratively attach policies to a named/typed client, while the factory manages lifecycle and pooling for you
|
Beta Was this translation helpful? Give feedback.
-
|
Here is a WCF client using Dependency Injection and Polly. I might change my current WCF client implementation to this. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
[1/22/2026: I have slightly refactored this post to reflect current updates to my approach.]
Many of the load test scenarios my organization wants be to run are complex, involving many different types of requests all running at various rates.
This post documents one way to achieve this in NBomber.
My basic idea here is to keep each scenario in a separate C# file, and separate the load test registration from the scenario (request) flows.
This separation of concerns makes for shorter C# files, and follows the pattern of classic load testing tools such as LoadRunner and Visual Studio where the load test with User/Thread specifications is in one file (e.g., xxx.loadtest) and the "script" or set of requests in the another (e.g., Flow01.webtest).
The approach below uses NBomber's "Run Multiple Scenarios in Parallel" model. But I have added a little code to assign users (threads) to each of the parallel-running scenarios in a fixed ratio. (see the dictionary at the top of the LoadTest class).
I think the same thing could be achieved by NBomber's built in "Scenario Distribution by Weight Probability" approach. (And I might switch my example below to using Distribution by Weight Probability. However, the code below makes talking about users easier. In much of my load testing experience, it is easier to talk to management about "users," rather than requests per second. The approach below will make a little more sense when I add pacing to the example.
Features of this Approach
-DataFeeds are declared in the LoadTest class. I can do this because in my application scenarios can use the same data. I can instantiate the data feeds in the LoadTest class, and then just call for a new user at the top of each scenario before I do an authenticate request. In the example below the scenario has the responsibility of instantiating the datafeed, but datafeeds are shared resource of the entire test. (Variations are possible here.)
File 01: The Load Test Class
Notice in the above that I am taking the number I got from Application Dynamics, the target transactions per hour, and passing it to a method which creates each load test for me. This main class, just registers the scenarios.
File 02: Scenario 01
File 03: Scenario 02
File 04: Scenario 03
Beta Was this translation helpful? Give feedback.
All reactions