How to send request immediately in WebClient Vert.x? - java

I want to benchmark my Restful API Server, so I send a ton of request to it to measure throughput and latency. I use Vert.x WebClient to create a client.
First, I create BenchmarkVerticle extends from AbstractVerticle and create a WebClient in start method.
public class BenchmarkVerticle extends AbstractVerticle {
#Override
public void start(Future<Void> future) {
WebClient client = WebClient.create(vertx);
while (true) {
// warm up in 10s and benchmark in 20s by sending requests
client.post(Server.port, "localhost", "/api")
.send(ar -> {
// do something after receiving response
});
}
}
}
And then I deploy BenchmarkVerticle in main
public static void main(String[] args) {
VertxOptions options = new VertxOptions();
options.setBlockedThreadCheckInterval(1000*60*60); // make BlockedThreadChecker not show
options.setWorkerPoolSize(40);
Vertx vertx = Vertx.vertx(options);
DeploymentOptions doptions = new DeploymentOptions()
.setWorker(true);
vertx.deployVerticle(new BenchmarkVerticle(), doptions);
}
I find that request are only sent when start method finished. I think each request is put in a queue to execute after method start complete. It affects to my benchmark result. I try using multithreading by setMultiThreaded(true) in DeploymentOptions object to make it send concurrently but it says:
java.lang.IllegalStateException: Cannot use HttpClient in a multi-threaded worker verticle
So how to make request send immediately in WebClient?
NOTE: English is not my native language. I will expain more detailed if you feel hard to understand.

i'm not sure i understand the setup. BenchmarkVerticle seems useless, unless it has more logic that you haven't revealed to in your post.
if BenchmarkVerticle is responsible for handing requests
remove the WebClient references from this class
be sure to call future.complete() at the end of the body of start()
...otherwise just remove it
then...
in the class that has the main() method
create the WebClient here
then deploy whatever Verticle(s) you need for your testing using the overloaded version of deployVerticle that allows your to supply a completionHandler:
deployVerticle(String name, DeploymentOptions options,
Handler> completionHandler)
the completion handler is called when your Verticle(s) are finally deployed. add your request + response handling inside this handler.

Related

How to make concurrent network requests using OKHTTP?

I'm looking for a best practice for making concurrent network requests using the OKHTTP library.
Basically here's what I want to do:
I want to write a method that makes N concurrent network requests to different URLs, and return ONLY when ALL N requests have returned.
I thought about manually writing Threads and Runnables and such to create a group of request pool, but was wondering if there's some sort of easier way to do this. So my question is:
Does OKHTTP support concurrent request API natively somehow?
If not, what's the best way to implement this?
OkHttp natively supports asynchronous requests efficiently e.g. sharing the optimum number of connections.
See https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/AsynchronousGet.java
For the second part of the question, you use a CountdownLatch or you can bridge to java Futures like the following
public class OkHttpResponseFuture implements Callback {
public final CompletableFuture<Response> future = new CompletableFuture<>();
public OkHttpResponseFuture() {
}
#Override public void onFailure(Call call, IOException e) {
future.completeExceptionally(e);
}
#Override public void onResponse(Call call, Response response) throws IOException {
future.complete(response);
}
}
And call
private Future<Response> makeRequest(OkHttpClient client, Request request) {
Call call = client.newCall(request);
OkHttpResponseFuture result = new OkHttpResponseFuture();
call.enqueue(result);
return result.future;
}
At that point you can use methods like CompletableFuture.allOf
n.b. if you wrap with Futures, it can be easy to not close the Response objects when one fails.

How can I call a function on start and periodically on Playframework 2.5

I need to make a WS petition when I start play so I can log in a external service to obtain a token. I need that token for make future petitions. I know how to make WS petitions, I don't know where to place that code to execute on start. At this time, it is in a function of a controller.
If you want some code of this:
// login data
ObjectNode tvdbaccount = Json.newObject();
tvdbaccount.put("apikey", "*****");
tvdbaccount.put("username", "*****");
tvdbaccount.put("userkey", "*****");
// try to login
String token = "";
CompletionStage<JsonNode> request = WS.url("https://api.thetvdb.com/login")
.post(tvdbaccount)
.thenApply(WSResponse::asJson);
try {
JsonNode response = request.toCompletableFuture()
.get(5, TimeUnit.SECONDS);
token = response.get("token").asText();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
That token expires after 24 hours so I want for example to call a function every 12 hours that refreshes that token. That function is similar to the previous one, it's only a WS petition.
I'm using playframework 2.5 where GlobalSettings is deprecated and I see multiple answers not very clear for 2.5 so I fail to get it done.
Thanks to Alexander B, I've been able to get what I wanted.
Eager Singleton
I resolved the on start function call with the eager singleton.
What I've done is a class for the TVDB things and the important part is to write what you want to do on start inside the constructor of this class. And then to bind it on a module:
bind(TVDB.class).asEagerSingleton();
Akka actors
For the periodically function call I used an Akka actor.
I've implemented an actor which calls itself every 12 hours, so I placed the scheduling code in the same actor on the preStart void. I think the Playframework documentation for the Scheduling asynchronous tasks isn't updated and doesn't work the way it is (at least for me).
Then, I binded it on the module:
bindActor(TVDBActor.class, "TVDBActor");
If someone need the actor code here it is:
public class TVDBActor extends UntypedActor {
#Inject
public void preStart(final ActorSystem system, #Named("TVDBActor") ActorRef tvdbActor) {
system.scheduler().schedule(
Duration.create(12, TimeUnit.HOURS),
Duration.create(12, TimeUnit.HOURS),
tvdbActor,
"tick",
system.dispatcher(),
null
);
}
#Override
public void onReceive(Object msg) throws Exception {
TVDB.refreshToken();
}
}

JAXRS Server check status

I have created a JAXRS SERVER for some web services. The server is working just fine, but I need to add a new feature so that I can check the server status at any time. So if the server is up I should return a message like running,and if is down a message like down.
My implementation so far:
public class Server
{
public static void main( final String[] args )
{
final JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean();
final SubscriptionService subscriptionService =
new SubscriptionService( SubscriptionRepo.getRepo() );
final SystemService systemservice = new SystemService();
serverFactory.setResourceProvider(new SingletonResourceProvider(subscriptionService));
serverFactory.setResourceProvider(new SingletonResourceProvider(systemservice));
serverFactory.setAddress( "http://localhost:8888" );
serverFactory.setProvider( JacksonJsonProvider.class );
serverFactory.create();
}
}
I have also created a service class where I want to get the status:
public class SystemService
{
#GET
#Path("/systemstatus")
public Response getSystemStatus()
{
return Response.status( Status.OK.getStatusCode() );
}
}
I really have no idea how can I return a status if the system is running or not.
Can anyone help me with some ideas on how to check the server status?
Your quest kind of collapses on itself when you consider that you're trying to get a response from a web service, that's deployed on a non-responsive web server. How exactly do you envisage your web service getting the word out (by way of a coherent HTTP status, no less), that it's not reachable? How are you even going to get to it in the first place? When the container is down, your service is not in a position to return any meaningful message to the client
Stick to time-tested exception handling in the various flavours of the connection-related SocketException and possibly the HttpRetryException, in some cases. That's all you're going to get when your server is not up: some variety of SocketException. Your REST service has no power here.

ThreadPool Vs Task Vs Async

I have the following code that shows sending an email. I can achieve this through ThreadPool, Task and Async. The caller (in this case Main) is not interested in what comes back.
As I understand, all three methods create an additional thread so the end result is the same.
Please share if you find any other difference, or which should be the right way in .NET 4.5?
PS. If you want to copy the code and run it, make sure you select the startup object in the project settings. You can select one of the startup Main methods.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncTest
{
class ThreadPoolProgram
{
static void Main(string[] args)
{
// Dont care what SendEmail returns
ThreadPool.QueueUserWorkItem(new WaitCallback(SendEmail));
}
static void SendEmail(Object stateInfo)
{
// Create a SMTP client, send an email and wait for the SMTP client to return!
// Takes 2 seconds
}
}
class TaskProgram
{
static void Main(string[] args)
{
// Dont care what SendEmail returns
Task.Run(() => SendEmail());
}
static void SendEmail()
{
// Create a SMTP client, send an email and wait for the SMTP client to return!
// Takes 2 seconds
}
}
class AsyncProgram
{
static void Main(string[] args)
{
// Don't await for an answer from the SendMail
// var r = await SendEmail();
SendEmail(); // Call without await
}
static Task<bool> SendEmail()
{
// Create a SMTP client, send an email and wait for the SMTP client to return!
// Takes 2 seconds
return Task.FromResult(true);
}
}
}
It seems a reasonable question but the context makes it hard to give a good answer.
You are using a Console program and Dont care what SendEmail returns. That is not the normal case.
async/await uses Tasks that run on top of the ThreadPool. so your 'vs' doesn't hold up. And normally you would at least care about errors that occurred.
When you really don't care about errors or results, QueueUserWorkItem() is the most basic approach.
In most contexts however you would aim for an awaitable Task. The SmtpClient.SendAsync() is not awaitable, so a Task that runs the synchronous Send() seems most appropriate.
And when it is really about sending (bulk) mails you would have a few other issues to tackle, like throttling the number of parallel calls.

Jersey Client, memory leak, static and concurrency

I am using Jersey Client (v2.17) to make external calls from my app.
I found out this memory leak bug (the CPU consumption was very high) which made me re-write my code to make the client static like this:
public class GeneralUtil {
private static final Client client = ClientBuilder.newClient()
public static String makeCall(String url) throws NotFoundException {
return client.target(url).request().get(String.class);
}
}
However, now I have concurrency problems - I am using this class to be called from multiple threads. I keep on getting:
org.apache.http.impl.execchain.RequestAbortedException: Request aborted
Any suggestion - how can I still prevent the memory leak, and still use the client?
If you don't want to create an arbitrary number of Client objects, you can use ThreadLocal and have one object per thread.
You can override ThreadLocal.initialValue to return ClientBuilder.newClient() to automate creation of Client objects for new threads.
Or you could make the methods synchronized, but that means that you will only be able to do one request at a time.
Here's some example code:
class GeneralUtil {
ThreadLocal<Client> client = new ThreadLocal<Client>() {
#Override
public Client initialValue() {
return ClientBuilder.newClient();
}
};
public static String makeCall(String url) throws NotFoundException {
return client.get().target(url).request().get(String.class);
}
...
}
As initially stated by Dejel, this is a known issue.
The "workarounds" work... but I believe this issue is critical and should be fixed by the Jersey team.
Let the Jersey team know that this affects YOU by logging in to JIRA and voting it up. It currently only has 3 votes :
https://java.net/jira/browse/JERSEY-2830

Resources