-
Notifications
You must be signed in to change notification settings - Fork 0
feature: add virtual threads to LoadEngine and validation tests #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,9 @@ | |
|
|
||
| import com.volta.http.HttpSender; | ||
| import java.net.http.HttpResponse; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
| import java.util.concurrent.Semaphore; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
|
|
@@ -12,20 +15,21 @@ public class LoadEngine { | |
| private final int targetRps; | ||
| private final int durationSeconds; | ||
| private volatile boolean running = false; | ||
| private static final int MAX_CONCURRENT_REQUESTS = 1000; | ||
|
|
||
| public LoadEngine(String URL, int targetRPS, int durationSeconds) { | ||
| if (URL == null || URL.isBlank()) { | ||
| public LoadEngine(String url, int targetRps, int durationSeconds) { | ||
| if (url == null || url.isBlank()) { | ||
| throw new IllegalArgumentException("URL must not be empty"); | ||
| } | ||
| if (targetRPS <= 0) { | ||
| if (targetRps <= 0) { | ||
| throw new IllegalArgumentException("RPS must be positive"); | ||
| } | ||
| if (durationSeconds <= 0) { | ||
| throw new IllegalArgumentException("Duration must be positive"); | ||
| } | ||
|
|
||
| this.url = URL; | ||
| this.targetRps = targetRPS; | ||
| this.url = url; | ||
| this.targetRps = targetRps; | ||
| this.durationSeconds = durationSeconds; | ||
| } | ||
|
|
||
|
|
@@ -35,25 +39,55 @@ public void start() { | |
| long endTime = System.nanoTime() + (long) durationSeconds * 1_000_000_000L; | ||
| long sendNextTime = System.nanoTime(); | ||
|
|
||
| try (HttpSender sender = new HttpSender()) { | ||
| Semaphore semaphore = new Semaphore(MAX_CONCURRENT_REQUESTS); | ||
|
|
||
| try (HttpSender sender = new HttpSender(); | ||
| ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { | ||
|
|
||
| while (running && System.nanoTime() < endTime) { | ||
|
|
||
| while (System.nanoTime() < sendNextTime) { | ||
| // busy-wait | ||
| long waitMillis = (sendNextTime - System.nanoTime()) / 1_000_000; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this calculation, |
||
|
|
||
| if (waitMillis > 0) { | ||
| try { | ||
| Thread.sleep(waitMillis); | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| HttpResponse<String> response = sender.send(url); | ||
| log.info("Status: {}, Body: {}", response.statusCode(), response.body()); | ||
| } catch (Exception e) { | ||
| log.error("Request failed", e); | ||
| semaphore.acquire(); | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| break; | ||
| } | ||
|
|
||
| executor.submit( | ||
| () -> { | ||
| try { | ||
| HttpResponse<String> response = sender.send(url); | ||
| log.info("Status: {}, Body: {}", response.statusCode(), response.body()); | ||
| } catch (Exception e) { | ||
| log.error("Request failed", e); | ||
| } finally { | ||
| semaphore.release(); | ||
| } | ||
| }); | ||
|
|
||
| if (System.nanoTime() - sendNextTime > 1_000_000_000L) { | ||
| sendNextTime = System.nanoTime(); | ||
| } | ||
|
|
||
| sendNextTime += intervalNanos; | ||
| } | ||
| } catch (Exception e) { | ||
| log.error("Sender closed or failed to initialize", e); | ||
| } | ||
|
|
||
| // try-with-resources handles executor.close() and sender.close() | ||
| running = false; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It’s not obvious how the entire process terminates |
||
| log.info("Test finished"); | ||
| } | ||
|
|
||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The number of threads can grow without limit, and eventually no amount of memory will be enough