Skip to content

Commit deca8bd

Browse files
committed
Add rate parameter to limit number of request being sent per second. Add help text to all commandline parameters
1 parent d56441d commit deca8bd

File tree

5 files changed

+81
-15
lines changed

5 files changed

+81
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "hammerload"
3-
version = "0.1.0"
3+
version = "0.3.0"
44
edition = "2021"
55

66
[dependencies]

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,18 @@ cargo build --release
2020
hammerload <PROTOCOL> --url <URL> [OPTIONS]
2121
```
2222

23+
Core load parameters
24+
```
25+
-d, --duration <SECONDS> Duration of test in seconds
26+
-c, --concurrency <N> Number of concurrent connections
27+
-r, --rate <N> Requests per second
28+
-t, --timeout <SECONDS> Timeout in seconds
29+
```
30+
2331
Request options
2432
```
25-
-X, --method <METHOD> HTTP method (GET, POST…)
33+
-u, --url <URL> URL to send requests to
34+
-X, --method <METHOD> HTTP method (GET, POST, PUT, PATCH, DELETE, ...)
2635
-H, --header <HEADER> Custom headers (repeatable)
2736
-b, --body <STRING> Request body
2837
-F, --form <KEY=VALUE> Form fields (repeatable)

src/main.rs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,68 @@ enum Protocol {
1313
#[derive(Parser, Debug)]
1414
#[command(
1515
author = "Your Name",
16-
version = "1.0.0",
16+
version = "0.3.0",
1717
about = "Hammerload - A load testing tool for HTTP protocols"
1818
)]
1919
struct Args {
2020
#[arg(value_name = "PROTOCOL")]
2121
protocol: Protocol,
2222

23-
#[arg(short = 'X', long, value_name = "METHOD", default_value = "GET")]
23+
#[arg(
24+
short = 'X',
25+
long,
26+
value_name = "METHOD",
27+
default_value = "GET",
28+
help = "HTTP method (GET, POST, PUT, PATCH, DELETE, ...)"
29+
)]
2430
method: Method,
2531

26-
#[arg(short, long, value_name = "URL")]
32+
#[arg(short, long, value_name = "URL", help = "URL to send requests to")]
2733
url: String,
2834

29-
#[arg(short, long, value_name = "BODY")]
35+
#[arg(short, long, value_name = "BODY", help = "Request body")]
3036
body: Option<String>,
3137

32-
#[arg(short, long, value_name = "CONCURRENCY", default_value_t = 1)]
38+
#[arg(short = 'H', long = "header", help = "Request header (repeatable)")]
39+
headers: Vec<String>,
40+
41+
#[arg(short = 'F', long = "form", help = "Form parameters (repeatable)")]
42+
form_params: Vec<String>,
43+
44+
#[arg(
45+
short,
46+
long,
47+
value_name = "CONCURRENCY",
48+
default_value_t = 1,
49+
help = "Number of concurrent connections"
50+
)]
3351
concurrency: u64,
3452

35-
#[arg(short, long, value_name = "DURATION", default_value_t = 10)]
53+
#[arg(
54+
short,
55+
long,
56+
value_name = "DURATION",
57+
default_value_t = 10,
58+
help = "Duration of test in seconds"
59+
)]
3660
duration: u64,
3761

38-
#[arg(short = 'H', long = "header")]
39-
headers: Vec<String>,
40-
41-
#[arg(short = 'F', long = "form")]
42-
form_params: Vec<String>,
62+
#[arg(
63+
short,
64+
long,
65+
value_name = "RATE",
66+
help = "Number of requests per second"
67+
)]
68+
rate: Option<u64>,
4369

4470
// timeout
45-
#[arg(short, long, value_name = "TIMEOUT", default_value_t = 5)]
71+
#[arg(
72+
short,
73+
long,
74+
value_name = "TIMEOUT",
75+
default_value_t = 5,
76+
help = "Request timeout in seconds"
77+
)]
4678
timeout: u64,
4779
}
4880

@@ -102,6 +134,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
102134
header_map,
103135
args.concurrency,
104136
args.duration,
137+
args.rate,
105138
args.timeout,
106139
);
107140

src/scheduler/scheduler.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct Scheduler<'a> {
1313
headers: HeaderMap,
1414
concurrency: u64,
1515
duration: u64,
16+
rate: Option<u64>,
1617
timeout: u64,
1718
}
1819

@@ -26,6 +27,7 @@ impl<'a> Scheduler<'a> {
2627
headers: HeaderMap,
2728
concurrency: u64,
2829
duration: u64,
30+
rate: Option<u64>,
2931
timeout: u64,
3032
) -> Self {
3133
Scheduler {
@@ -37,6 +39,7 @@ impl<'a> Scheduler<'a> {
3739
headers,
3840
concurrency,
3941
duration,
42+
rate,
4043
timeout,
4144
}
4245
}
@@ -54,7 +57,9 @@ impl<'a> Scheduler<'a> {
5457
let body = self.body.clone();
5558
let form_params = self.form_params.clone();
5659
let headers = headers.clone();
60+
let concurrency = self.concurrency;
5761
let duration = self.duration;
62+
let rate = self.rate;
5863
let timeout = self.timeout;
5964
let metrics = Arc::clone(self.metrics);
6065

@@ -67,7 +72,9 @@ impl<'a> Scheduler<'a> {
6772
body,
6873
form_params,
6974
headers,
75+
concurrency,
7076
duration,
77+
rate,
7178
timeout,
7279
)
7380
.await;
@@ -113,7 +120,9 @@ impl<'a> Scheduler<'a> {
113120
body: Option<String>,
114121
form_params: HashMap<String, String>,
115122
headers: HeaderMap,
123+
concurrency: u64,
116124
duration: u64,
125+
rate: Option<u64>,
117126
timeout: u64,
118127
) {
119128
let client = Client::builder()
@@ -122,14 +131,29 @@ impl<'a> Scheduler<'a> {
122131
.build()
123132
.unwrap();
124133

134+
let interval = rate.map(|rps| {
135+
let per_worker = (rps as f64) / (concurrency as f64);
136+
Duration::from_secs_f64(1.0 / per_worker)
137+
});
138+
125139
loop {
140+
let loop_start = std::time::Instant::now();
141+
126142
let result =
127143
Self::make_request(metrics, &client, &method, &url, &body, &form_params).await;
128144
Self::handle_request_result(metrics, result).await;
129145

130146
if std::time::Instant::now() >= start_bench + std::time::Duration::from_secs(duration) {
131147
break;
132148
}
149+
150+
// Enforce rate limiting
151+
if let Some(interval) = interval {
152+
let elapsed = loop_start.elapsed();
153+
if elapsed < interval {
154+
tokio::time::sleep(interval - elapsed).await;
155+
}
156+
}
133157
}
134158
}
135159

0 commit comments

Comments
 (0)