Swarm

An elegant Java client for Locust

1. Motivation

IMHO, Locust4j a basic implementation for Locust clients written in Java. It has so many restrictions, including:

Based on implementation of Locust4j, Swarm is completely re-written to address all issues above, with some additional features:

2. Implementation

3. Installation

Before using Swarm, you must declare it as a dependency of your Maven project. For example:

<dependency>
    <groupId>com.bigsonata.swarm</groupId>
    <artifactId>locust-swarm</artifactId>
    <version>1.1.4</version>
</dependency>

You also have to add following dependencies:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>org.msgpack</groupId>
    <artifactId>msgpack-core</artifactId>
    <version>0.8.13</version>
</dependency>

<dependency>
    <groupId>org.zeromq</groupId>
    <artifactId>jeromq</artifactId>
    <version>0.4.3</version>
</dependency>

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.7</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>23.0</version>
</dependency>

4. How to write your benchmarks

4.1 Overview

Swarm uses the term of Cron to refer to repeating tasks defined by you.

Life cycle of a Cron-based instance can be described in the following diagram:

Swarm is responsible for cloning, initializing crons.

4.2 Cron anatomy
// Here is an abridged version of class Cron
public abstract class Cron implements Cloneable, Runnable {
    public Cron(Props props) {
        this.props = props;
    }

    public abstract void process();

    public abstract Cron clone();

    public void recordFailure(long responseTime, String error) {
        // ..
    }

    public void recordSuccess(long responseTime, long contentLength) {
        // ..
    }

    public void recordSuccess(long responseTime) {
        // ..
    }

    @Override
    public void run() {
        // ...
        process();
    }

    public abstract void dispose();

    public abstract void initialize();
}

Each cron has its own props which defines type & name (to display on the Web interface):

public class Props {
    protected String type = "default";
    protected String name = "cron";
    protected int weight = 1;
    protected boolean async = false;

    public static Props create() {
        return new Props();
    }

    public static Props createAsync() {
        return new Props()
                .setAsync(true);
    }

    public Props setType(String type) {
        // ..
    }

    public Props setName(String name) {
        // ..
    }

    public Props setWeight(int weight) {
        // ..
    }

    public Props setAsync(boolean async) {
        // ..
    }
}

NOTE: A cron must specify how it works: synchronously or asynchronously

Inside each cron, there are 4 must-overridden methods

4.3 Define your crons

You need to define your loading test by deriving class Cron:

For example, in our AsyncCron:

public class TimerCron extends Cron {
  public TimerCron() {
    super(Props.create().setName("timer").setAsync(false));
  }

  @Override
  public void process() {
    try {
      System.out.println("> Processing...");
      long start = System.currentTimeMillis();
      Thread.sleep(1000);
      long duration = System.currentTimeMillis() - start;
      recordSuccess(duration);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  @Override
  public Cron clone() {
    return new TimerCron();
  }

  @Override
  public void dispose() {}

  @Override
  public void initialize() {}
}
4.4 Finalize

After defining your crons, finally you need to instruct Swarm to start:

Locust.Builder.newInstance()
    .setMasterHost(masterHost)
    .setMasterPort(masterPort)

    // Optionally set the interval (in ms) to report statistics
    // Default: 2000
    .setStatInterval(2000)

    // Optionally set a seed number to generate nodeId
    .setRandomSeed(0)

    // Optionally set the number of threads to stimulate Crons
    // Default: 8
    .setThreads(8)

    // Optionally set the number of maximum requests per second
    .setMaxRps(1000)

    // Register cron tasks
    .setCrons(new TimerCron());
    .build()

5. Tips

6. Contributions

If you find anything wrong or would like to contribute in any way, feel free to create a pull request/open an issue/send me a message. Any comments are welcome!

7. History

v1.1.4

v1.1.3

v1.1.0

v1.0.1

v1.0.0

v0.1.2

v0.1.0