简体   繁体   English

如何使Vertx MongoClient操作同步但不阻止Java中的事件循环?

[英]How to make Vertx MongoClient operation synchronous yet not blocking event loop in Java?

I am trying to save a new document to MongoDB using the Vertx MongoClient as follows: 我正在尝试使用Vertx MongoClient将新文档保存到MongoDB,如下所示:

MongoDBConnection.mongoClient.save("booking", query, res -> {
    if(res.succeeded()) {
        documentID = res.result();
        System.out.println("MongoDB inserted successfully. + document ID is : " + documentID);
    }
    else {
        System.out.println("MongoDB insertion failed.");
    }
});

if(documentID != null) {

    // MongoDB document insertion successful. Reply with a booking ID
    String resMsg = "A confirmed booking has been successfully created with booking id as " + documentID + 
        ". An email has also been triggered to the shared email id " + emailID;

    documentID = null;

    return new JsonObject().put("fulfillmentText", resMsg);
}
else {
    // return intent response
    documentID = null;
    return new JsonObject().put("fulfillmentText", 
        "There is some issues while booking the shipment. Please start afreash.");
}

The above code successfully writes the query jsonObject to MongoDB collection booking . 上面的代码成功地将查询jsonObject写入MongoDB集合booking However, the function which contains this code always returns with There is some issues while booking the shipment. Please start afreash 但是,包含此代码的函数始终以形式返回There is some issues while booking the shipment. Please start afreash There is some issues while booking the shipment. Please start afreash . There is some issues while booking the shipment. Please start afreash

This is happening probably because the MongoClient save() handler "res" is asynchronous. 发生这种情况可能是因为MongoClient save()处理程序“ res”是异步的。 But, I want to return conditional responses based on successful save() operation and on failed save operation. 但是,我想基于成功的save()操作和失败的保存操作返回条件响应。

How to achieve it in Vertx Java? 如何在Vertx Java中实现?

Your assumption is correct, you dont wait for the async response from the database. 您的假设是正确的,您不必等待数据库的异步响应。 What you can do, is to wrap it in a Future like this: 您可以做的是将其包装在Future中,如下所示:

  public Future<JsonObject> save() {
    Future<JsonObject> future = Future.future();
    MongoDBConnection.mongoClient.save("booking", query, res -> {
      if(res.succeeded()) {
        documentID = res.result();
        if(documentID != null) {
          System.out.println("MongoDB inserted successfully. + document ID is : " + documentID);
          String resMsg = "A confirmed booking has been successfully created with booking id as " + documentID +
            ". An email has also been triggered to the shared email id " + emailID;
          future.complete(new JsonObject().put("fulfillmentText", resMsg));
        }else{
          future.complete(new JsonObject().put("fulfillmentText",
            "There is some issues while booking the shipment. Please start afreash."))
        }
      } else {
        System.out.println("MongoDB insertion failed.");
        future.fail(res.cause());
      }
    });
    return future;
  }

Then i assume you have and endpoint that eventually calls this, eg: 然后,我假设您有最终调用此方法的端点,例如:

router.route("/book").handler(this::addBooking);

... then you can call the save method and serve a different response based on the result ...然后您可以调用save方法并根据结果提供不同的响应

public void addBooking(RoutingContext ctx){
    save().setHandler(h -> {
        if(h.succeeded()){
            ctx.response().end(h.result());
        }else{
            ctx.response().setStatusCode(500).end(h.cause());
        }
    })
}

You can use RxJava 2 and a reactive Mongo Client ( io.vertx.reactivex.ext.mongo.MongoClient ) 您可以使用RxJava 2反应式Mongo Clientio.vertx.reactivex.ext.mongo.MongoClient

Here is a code snippet: 这是一个代码片段:

Deployer 部署者

public class Deployer extends AbstractVerticle {

   private static final Logger logger = getLogger(Deployer.class);

   @Override
   public void start(Future<Void> startFuture) {
      DeploymentOptions options = new DeploymentOptions().setConfig(config());

      JsonObject mongoConfig = new JsonObject()
            .put("connection_string",
                  String.format("mongodb://%s:%s@%s:%d/%s",
                        config().getString("mongodb.username"),
                        config().getString("mongodb.password"),
                        config().getString("mongodb.host"),
                        config().getInteger("mongodb.port"),
                        config().getString("mongodb.database.name")));

      MongoClient client = MongoClient.createShared(vertx, mongoConfig);

      RxHelper.deployVerticle(vertx, new BookingsStorage(client), options)
            .subscribe(e -> {
               logger.info("Successfully Deployed");
               startFuture.complete();
            }, error -> {
               logger.error("Failed to Deployed", error);
               startFuture.fail(error);
            });
   }
}

BookingsStorage 预订存储

public class BookingsStorage extends AbstractVerticle {

   private MongoClient mongoClient;

   public BookingsStorage(MongoClient mongoClient) {
      this.mongoClient = mongoClient;
   }

   @Override
   public void start() {
      var eventBus = vertx.eventBus();
      eventBus.consumer("GET_ALL_BOOKINGS_ADDRESS", this::getAllBookings);
   }

   private void getAllBookings(Message msg) {
      mongoClient.rxFindWithOptions("GET_ALL_BOOKINGS_COLLECTION", new JsonObject(), sortByDate())
            .subscribe(bookings -> {
                     // do something with bookings
                     msg.reply(bookings);
                  },
                  error -> {
                     fail(msg, error);
                  }
            );
   }

   private void fail(Message msg, Throwable error) {
      msg.fail(500, "An unexpected error occurred: " + error.getMessage());
   }

   private FindOptions sortByDate() {
      return new FindOptions().setSort(new JsonObject().put("date", 1));
   }
}

HttpRouterVerticle HttpRouterVerticle

// inside a router handler: 

 vertx.eventBus().rxSend("GET_ALL_BOOKINGS_ADDRESS", new JsonObject())
                 .subscribe(bookings -> {
                     // do something with bookings
                  },
                    e -> {
                      // handle error
                 }); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM