Load Testing with
Virtual Threads

Open source, high-concurrency load testing framework built on Java 21. Achieve 10,000+ TPS with minimal memory footprint using Project Loom's virtual threads. Released under Apache License 2.0.

๐Ÿ”“ Open Source โš–๏ธ Apache 2.0 Java 21 Virtual Threads Minimal Dependencies OpenTelemetry
HttpLoadTest.java
@VirtualThreads
public class HttpLoadTest implements Task {
    private HttpClient client;
    
    @Override
    public void setup() {
        client = HttpClient.newBuilder()
            .executor(Executors.newVirtualThreadPerTaskExecutor())
            .build();
    }
    
    @Override
    public TaskResult execute() {
        var response = client.send(request, ...);
        return TaskResult.success(response.body());
    }
}

Powerful Features

Everything you need for modern load testing

โšก

Virtual Threads

Leverage Java 21's Project Loom for millions of concurrent operations with minimal memory overhead. Perfect for I/O-bound load tests.

๐Ÿ“Š

Flexible Load Patterns

Six built-in patterns: Static, Ramp-up, Ramp-sustain, Step, Spike, and Sine wave. Model any real-world traffic scenario.

๐Ÿ“ˆ

Rich Metrics

Micrometer-based metrics with percentile calculations. Export to OpenTelemetry, console, or custom backends.

๐Ÿ”Œ

Simple API

Just implement the Task interface with setup(), execute(), and cleanup(). The framework handles the rest.

๐ŸŽฏ

Thread Strategy

Choose virtual threads for I/O-bound tasks or platform threads for CPU-intensive workloads. Annotate and go.

๐Ÿš€

High Performance

10,000+ TPS per worker, millions of concurrent requests, all with minimal resource consumption.

Why VajraPulse?

Built for the modern Java ecosystem

01

Java 21 First

Built exclusively for Java 21, leveraging records, sealed types, pattern matching, and virtual threads. No legacy baggage.

02

Minimal Dependencies

Core API has zero dependencies. Full framework weighs in at just ~1.6MB. Every dependency is justified and minimal.

03

Production Ready

Comprehensive test coverage (โ‰ฅ90%), OpenTelemetry integration, and battle-tested patterns. Ready for production workloads.

04

Developer Friendly

Simple, intuitive API. Clear documentation. Working examples. Get started in minutes, not hours.

Code Examples

See how easy it is to get started

Creating a Simple HTTP Load Test

import com.vajrapulse.api.*;

@VirtualThreads  // Use virtual threads for I/O
public class HttpLoadTest implements Task {
    private HttpClient client;
    private HttpRequest request;
    
    @Override
    public void setup() throws Exception {
        client = HttpClient.newBuilder()
            .executor(Executors.newVirtualThreadPerTaskExecutor())
            .connectTimeout(Duration.ofSeconds(10))
            .build();
        
        request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/endpoint"))
            .timeout(Duration.ofSeconds(10))
            .GET()
            .build();
    }
    
    @Override
    public TaskResult execute() throws Exception {
        HttpResponse response = client.send(
            request, 
            HttpResponse.BodyHandlers.ofString()
        );
        
        if (response.statusCode() == 200) {
            return TaskResult.success(response.body());
        } else {
            return TaskResult.failure(
                new RuntimeException("HTTP " + response.statusCode())
            );
        }
    }
    
    @Override
    public void cleanup() throws Exception {
        // Cleanup resources if needed
    }
}

Load Pattern Examples

import com.vajrapulse.api.*;
import java.time.Duration;

// Static: Constant TPS
LoadPattern staticPattern = new StaticLoad(
    100.0, 
    Duration.ofMinutes(5)
);

// Ramp-up: Linear increase from 0 to max
LoadPattern rampPattern = new RampUpLoad(
    500.0, 
    Duration.ofSeconds(30)
);

// Ramp-sustain: Ramp then maintain
LoadPattern rampSustain = new RampUpToMaxLoad(
    500.0, 
    Duration.ofSeconds(30),  // ramp duration
    Duration.ofMinutes(5)      // total duration
);

// Step: Discrete phases
LoadPattern stepPattern = new StepLoad(List.of(
    new StepLoad.Step(50.0, Duration.ofSeconds(30)),
    new StepLoad.Step(200.0, Duration.ofMinutes(1)),
    new StepLoad.Step(500.0, Duration.ofMinutes(2))
));

// Sine: Smooth oscillation
LoadPattern sinePattern = new SineWaveLoad(
    300.0,                    // mean rate
    150.0,                     // amplitude
    Duration.ofMinutes(3),     // total duration
    Duration.ofSeconds(20)     // period
);

// Spike: Periodic bursts
LoadPattern spikePattern = new SpikeLoad(
    200.0,                     // base rate
    800.0,                     // spike rate
    Duration.ofMinutes(2),     // total duration
    Duration.ofSeconds(15),    // spike interval
    Duration.ofSeconds(3)      // spike duration
);

Programmatic Execution

import com.vajrapulse.api.*;
import com.vajrapulse.core.metrics.AggregatedMetrics;
import com.vajrapulse.exporter.console.ConsoleMetricsExporter;
import com.vajrapulse.worker.pipeline.MetricsPipeline;
import java.time.Duration;

public class LoadTestRunner {
    public static void main(String[] args) throws Exception {
        // Create your task
        HttpLoadTest task = new HttpLoadTest();
        
        // Define load pattern
        LoadPattern pattern = new StaticLoad(
            100.0, 
            Duration.ofSeconds(30)
        );
        
        // Build metrics pipeline with exporters
        try (MetricsPipeline pipeline = MetricsPipeline.builder()
            .addExporter(new ConsoleMetricsExporter())
            .withPeriodic(Duration.ofSeconds(5))  // Live updates
            .withPercentiles(0.5, 0.95, 0.99)
            .build()) {
            
            // Run the test
            pipeline.run(task, pattern);
        }
        
        // Automatic cleanup
    }
}

Command Line Interface

# Static pattern
java -jar vajrapulse-worker-all.jar \
  com.example.HttpLoadTest \
  --mode static \
  --tps 100 \
  --duration 5m

# Ramp-up pattern
java -jar vajrapulse-worker-all.jar \
  com.example.HttpLoadTest \
  --mode ramp \
  --tps 200 \
  --ramp-duration 30s

# Ramp-sustain pattern
java -jar vajrapulse-worker-all.jar \
  com.example.HttpLoadTest \
  --mode ramp-sustain \
  --tps 200 \
  --ramp-duration 30s \
  --duration 5m

# Step pattern
java -jar vajrapulse-worker-all.jar \
  com.example.HttpLoadTest \
  --mode step \
  --steps "50@30s,200@1m,500@2m,100@30s"

# Sine wave pattern
java -jar vajrapulse-worker-all.jar \
  com.example.HttpLoadTest \
  --mode sine \
  --mean-rate 300 \
  --amplitude 150 \
  --period 120s \
  --duration 15m

# Spike pattern
java -jar vajrapulse-worker-all.jar \
  com.example.HttpLoadTest \
  --mode spike \
  --base-rate 100 \
  --spike-rate 800 \
  --spike-interval 60s \
  --spike-duration 5s \
  --duration 10m

Get Started

Add VajraPulse to your project in minutes

Using BOM (Recommended)

dependencies {
    // Import BOM
    implementation(platform("com.vajrapulse:vajrapulse-bom:0.9.3"))
    
    // Use modules without versions
    implementation("com.vajrapulse:vajrapulse-core")
    implementation("com.vajrapulse:vajrapulse-worker")
    
    // Optional exporters
    implementation("com.vajrapulse:vajrapulse-exporter-console")
    implementation("com.vajrapulse:vajrapulse-exporter-opentelemetry")
}

Using BOM (Recommended)

dependencies {
    // Import BOM
    implementation platform('com.vajrapulse:vajrapulse-bom:0.9.3')
    
    // Use modules without versions
    implementation 'com.vajrapulse:vajrapulse-core'
    implementation 'com.vajrapulse:vajrapulse-worker'
    
    // Optional exporters
    implementation 'com.vajrapulse:vajrapulse-exporter-console'
    implementation 'com.vajrapulse:vajrapulse-exporter-opentelemetry'
}

Using BOM (Recommended)

<dependencyManagement>
    <dependencies>
        <!-- Import BOM -->
        <dependency>
            <groupId>com.vajrapulse</groupId>
            <artifactId>vajrapulse-bom</artifactId>
            <version>0.9.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- Use modules without versions -->
    <dependency>
        <groupId>com.vajrapulse</groupId>
        <artifactId>vajrapulse-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.vajrapulse</groupId>
        <artifactId>vajrapulse-worker</artifactId>
    </dependency>
</dependencies>

Requirements

  • Java 21 or higher
  • Gradle 9.0+ or Maven 3.6+

Performance Benchmarks

10,000+
TPS per Worker
1M+
Concurrent Requests
~200 MB
Memory Usage
1.6 MB
Fat JAR Size
๐Ÿ”“

Open Source & Free

VajraPulse is completely open source and free to use. Released under the Apache License 2.0, you can use it in commercial and personal projects without restrictions.

โš–๏ธ

Apache License 2.0

Permissive open source license that allows you to:

  • โœ… Use commercially
  • โœ… Modify and distribute
  • โœ… Use in proprietary software
  • โœ… Patent use granted
Read Full License
๐Ÿ’ก

Contribute & Collaborate

VajraPulse is built by the community, for the community. Contributions are welcome!

  • โœ… Open source on GitHub
  • โœ… Community-driven development
  • โœ… Issue tracking and PRs welcome
  • โœ… Transparent development process
View on GitHub