1

I have a vertx application where I deploy multiple instances of verticle A (HttpVerticle.java) and multiple instances of verticle B (AerospikeVerticle.java). The aerospike verticles need to share a single AerospikeClient. The HttpVerticle listens to port 8888 and calls AerospikeVerticle using the event bus. My questions are:

  1. Is using sharedData the right way to share singleton client instances? Is there any other recommended / cleaner approach? I plan to create and share more such singleton objects (cosmos db clients, meterRegistry etc.) in the application. I plan to use sharedData.localMap to share them in a similar fashion.
  2. Is it possible to use vertx's eventloop as the backing eventloop for aerospike client? Such that the aerospike client initialisation does not need to create its own new eventloop? Currently looks like the onRecord part of the aerospike get call runs on aerospike's eventloop.
public class SharedAerospikeClient implements Shareable {
  public final EventLoops aerospikeEventLoops;
  public final AerospikeClient client;

  public SharedAerospikeClient() {
    EventPolicy eventPolicy = new EventPolicy();
    aerospikeEventLoops = new NioEventLoops(eventPolicy,  2 * Runtime.getRuntime().availableProcessors());
    ClientPolicy clientPolicy = new ClientPolicy();
    clientPolicy.eventLoops = aerospikeEventLoops;
    client = new AerospikeClient(clientPolicy, "localhost", 3000);
  }
}

Main.java

public class Main {
  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    LocalMap localMap = vertx.sharedData().getLocalMap("SHARED_OBJECTS");
    localMap.put("AEROSPIKE_CLIENT", new SharedAerospikeClient());
    vertx.deployVerticle("com.demo.HttpVerticle", new DeploymentOptions().setInstances(2 * 4));
    vertx.deployVerticle("com.demo.AerospikeVerticle", new DeploymentOptions().setInstances(2 * 4));
  }
}

HttpVerticle.java

public class HttpVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    vertx.createHttpServer().requestHandler(req -> {
      vertx.eventBus().request("read.aerospike", req.getParam("id"), ar -> {
        req.response()
          .putHeader("content-type", "text/plain")
          .end(ar.result().body().toString());
        System.out.println(Thread.currentThread().getName());
      });
    }).listen(8888, http -> {
      if (http.succeeded()) {
        startPromise.complete();
        System.out.println("HTTP server started on port 8888");
      } else {
        startPromise.fail(http.cause());
      }
    });
  }
}

AerospikeVerticle.java

public class AerospikeVerticle extends AbstractVerticle {
  private SharedAerospikeClient sharedAerospikeClient;

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    EventBus eventBus = vertx.eventBus();
    sharedAerospikeClient = (SharedAerospikeClient) vertx.sharedData().getLocalMap("SHARED_OBJECTS").get("AEROSPIKE_CLIENT");
    MessageConsumer<String> consumer = eventBus.consumer("read.aerospike");
    consumer.handler(this::getRecord);
    System.out.println("Started aerospike verticle");
    startPromise.complete();
  }

  public void getRecord(Message<String> message) {
    sharedAerospikeClient.client.get(
      sharedAerospikeClient.aerospikeEventLoops.next(),
      new RecordListener() {
        @Override
        public void onSuccess(Key key, Record record) {
            if (record != null) {
              String result = record.getString("value");
              message.reply(result);
            } else {
              message.reply("not-found");
            }
        }

        @Override
        public void onFailure(AerospikeException exception) {
            message.reply("error");
        }
      },
      sharedAerospikeClient.client.queryPolicyDefault,
      new Key("myNamespace", "mySet", message.body())
    );
  }
}

1 Answers1

4

I don't know about the Aerospike Client.

Regarding sharing objects between verticles, indeed shared data maps are designed for this purpose.

However, it is easier to:

  1. create the shared client in your main class or custom launcher
  2. provide the client as a parameter of the verticle constructor

The Vertx interface has a deployVerticle(Supplier<Verticle>, DeploymentOptions) method which is convenient in this case:

MySharedClient client = initSharedClient();
vertx.deploy(() -> new SomeVerticle(client), deploymentOptions);
tsegismont
  • 8,591
  • 1
  • 17
  • 27