An alternative would be to use ExecutorService
Basic Example:
RpcResult.class:
public class RpcResult {
private int clientId;
private String response;
// getters and setters...
}
RpcExecutor.class:
public class RpcExecutor implements Callable<RpcResult>{
private int clientId;
public RpcExecutor(int clientId) {
this.clientId = clientId;
}
public RpcResult call() throws Exception {
RpcResult result = new RpcResult();
result.setClientId(clientId);
result.setResponse("Resposta do cliente: " + clientId);
return result;
}
}
Execution:
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Callable<RpcResult>> list = new ArrayList<Callable<RpcResult>>();
for (int i = 1; i <= 3; i++) {
list.add(new RpcExecutor(i));
}
// 3 segundos de timeout
List<Future<RpcResult>> future = executor.invokeAll(list, 3L, TimeUnit.SECONDS);
for(Future<RpcResult> f : future) {
try {
if (!f.isCancelled()) {
RpcResult result = f.get();
System.out.println(result.getClientId());
System.out.println(result.getResponse());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
};
executor.shutdown();
To simulate a client's timeout, simply add a Thread.sleep () method in the call () method of the RpcExecutor class:
public RpcResult call() throws Exception {
if (clientId == 2)
Thread.sleep(15000);
RpcResult result = new RpcResult();
result.setClientId(clientId);
result.setResponse("Resposta do cliente: " + clientId);
return result;
}
EDIT
According to the new information related to the current project structure, this solution would not have scalability.
If you have in mind that your application will never have many users, okay, go in the simplest solution. Now, if your application needs to scale, this could be one of the alternatives (simplified model):