Vert.x httpclient - 3.5.0 throws exception "Connection was closed" intermittently - json

I have vert.x app which is consuming api REST over json but intermittently I am seeing exception with reason "Connection was closed". Below are my details -
please share your inputs if anything wrong in the configuration. may be creating scheduler or instantiating httpclient ?
on a different note is it advisable to use same http client to call more than 1 different api's on the same host and port ?
Vert.x Version: 3.5.0
import io.vertx.core.http.HttpClient;
private static Scheduler scheduler =
Schedulers.from(Executors.newFixedThreadPool(8));
// http client instantiated at the time of verticle startup
HttpClient httpclient = vertx.createHttpClient(getHttpClientOptions());
public static HttpClientOptions getHttpClientOptions() {
return new HttpClientOptions()
.setKeepAlive(true)
.setMaxPoolSize(100)
.setPipelining(true)
.setDefaultHost(xxxx.xxxx.com)
.setDefaultPort(8084)
.setSsl(true);
}
// invoke api call
public static Single<Response> invokePOSTServiceAsync(String reqBodyStr, String endpointURI) throws Exception {
try{
return Single.create((SingleEmitter<Response> emitter) -> {
HttpClientRequest request = httpClient.post(endpointURI);
request.putHeader("Content-type","application/json")
request.exceptionHandler(error -> {
LOG.error("ExceptionHandler "+error.getMessage());
emitter.onError(new Throwable(" Failure"));
})
.handler(response -> {
int statusCode = response.statusCode();
if (statusCode == 200) {
response.bodyHandler(body -> {
StringBuilder responseData = new StringBuilder();
responseData.append(body);
emitter.onSuccess(new Response(statusCode,responseData.toString(),"","",null));
});
} else {
emitter.onError(new Throwable(" Failure"));
}
})
.putHeader(HttpHeaders.CONTENT_LENGTH, reqBodyStr.length() + "")
.setTimeout(6000)
.write(reqBodyStr)
.end();
}).subscribeOn(scheduler);
}catch(Exception exe){
exe.printStackTrace();
return null;
}
}

My guess is that this is not related to the client. Either your server is being overloaded, or your network is unreliable. If you're consuming service which doesn't belong to you, you also may get throttled, and that's the reason you're seeing this.
In any case, you need to circumvent those problems, as the network is unreliable anyway. Make your POST requests idempotent and introduce retries.

Related

Spring AMQP RPC consumer and throw exception

I have a consumer (RabbitListner) in RPC mode and I would like to know if it is possible to throw exception that can be treated by the publisher.
To make more clear my explication the case is as follow :
The publisher send a message in RPC mode
The consumer receive the message, check the validity of the message and if the message can not be take in count, because of missing parameters, then I would like to throw Exception. The exception can be a specific business exception or a particular AmqpException but I want that the publisher can handle this exception if it is not go in timeout.
I try with the AmqpRejectAndDontRequeueException, but my publisher do not receive the exception, but just a response which is empty.
Is it possible to be done or may be it is not a good practice to implement like that ?
EDIT 1 :
After the #GaryRussel response here is the resolution of my question:
For the RabbitListner I create an error handler :
#Configuration
public class RabbitErrorHandler implements RabbitListenerErrorHandler {
#Override public Object handleError(Message message, org.springframework.messaging.Message<?> message1, ListenerExecutionFailedException e) {
throw e;
}
}
Define the bean into a configuration file :
#Configuration
public class RabbitConfig extends RabbitConfiguration {
#Bean
public RabbitTemplate getRabbitTemplate() {
Message.addWhiteListPatterns(RabbitConstants.CLASSES_TO_SEND_OVER_RABBITMQ);
return new RabbitTemplate(this.connectionFactory());
}
/**
* Define the RabbitErrorHandle
* #return Initialize RabbitErrorHandle bean
*/
#Bean
public RabbitErrorHandler rabbitErrorHandler() {
return new RabbitErrorHandler();
}
}
Create the #RabbitListner with parameters where rabbitErrorHandler is the bean that I defined previously :
#Override
#RabbitListener(queues = "${rabbit.queue}"
, errorHandler = "rabbitErrorHandler"
, returnExceptions = "true")
public ReturnObject receiveMessage(Message message) {
For the RabbitTemplate I set this attribute :
rabbitTemplate.setMessageConverter(new RemoteInvocationAwareMessageConverterAdapter());
When the messsage threated by the consumer, but it sent an error, I obtain a RemoteInvocationResult which contains the original exception into e.getCause().getCause().
See the returnExceptions property on #RabbitListener (since 2.0). Docs here.
The returnExceptions attribute, when true will cause exceptions to be returned to the sender. The exception is wrapped in a RemoteInvocationResult object.
On the sender side, there is an available RemoteInvocationAwareMessageConverterAdapter which, if configured into the RabbitTemplate, will re-throw the server-side exception, wrapped in an AmqpRemoteException. The stack trace of the server exception will be synthesized by merging the server and client stack traces.
Important
This mechanism will generally only work with the default SimpleMessageConverter, which uses Java serialization; exceptions are generally not "Jackson-friendly" so can’t be serialized to JSON. If you are using JSON, consider using an errorHandler to return some other Jackson-friendly Error object when an exception is thrown.
What worked for me was :
On "serving" side :
Service
#RabbitListener(id = "test1", containerFactory ="BEAN CONTAINER FACTORY",
queues = "TEST QUEUE", returnExceptions = "true")
DataList getData() {
// this exception will be transformed by rabbit error handler to a RemoteInvocationResult
throw new IllegalStateException("mon expecion");
//return dataHelper.loadAllData();
}
On "requesting" side :
Service
public void fetchData() throws AmqpRemoteException {
var response = (DataList) amqpTemplate.convertSendAndReceive("TEST EXCHANGE", "ROUTING NAME", new Object());
Optional.ofNullable(response)
.ifPresentOrElse(this::setDataContent, this::handleNoData);
}
Config
#Bean
AmqpTemplate amqpTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
var rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter);
return rabbitTemplate;
}
#Bean
MessageConverter jsonMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.registerModule(new JavaTimeModule());
var jsonConverter = new Jackson2JsonMessageConverter(objectMapper);
DefaultClassMapper classMapper = new DefaultClassMapper();
Map<String, Class<?>> idClassMapping = Map.of(
DataList.class.getName(), DataList.class,
RemoteInvocationResult.class.getName(), RemoteInvocationResult.class
);
classMapper.setIdClassMapping(idClassMapping);
jsonConverter.setClassMapper(classMapper);
// json converter with returned exception awareness
// this will transform RemoteInvocationResult into a AmqpRemoteException
return new RemoteInvocationAwareMessageConverterAdapter(jsonConverter);
}
You have to return a message as an error, which the consuming application can choose to treat as an exception. However, I don't think normal exception handling flows apply with messaging. Your publishing application (the consumer of the RPC service) needs to know what can go wrong and be programmed to deal with those possibilities.

How to update target host of a request in Apache HttpClient?

Our signing algorithm update HttpRequests by changing also the target
host of a request.
However, org.apache.http.impl.execchain.ProtocolExec#execute that prepares a given request for sending, computes target host before any HttpRequestInterceptor instance is run. Hence, even if HttpRequestInterceptor updates target host of a request, the request will be sent to the original host.
How can I update request target host so that the request is sent to an updated host?
I'm using httpclient 4.5.2.
Try decorating the protocol executor and rewriting the origin request prior passing it down the execution pipeline
CloseableHttpClient client = new HttpClientBuilder() {
#Override
protected ClientExecChain decorateProtocolExec(final ClientExecChain protocolExec) {
return new ClientExecChain() {
#Override
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext clientContext,
final HttpExecutionAware execAware) throws IOException, HttpException {
HttpUriRequest newRequest = RequestBuilder.copy(request.getOriginal())
.setUri("http://some-place-esle.com/")
.build();
return protocolExec.execute(route, HttpRequestWrapper.wrap(newRequest), clientContext, execAware);
}
};
}
}.build();

Error trying to connect to an mvc server on ms-azure from a windows phone 8 app using webapi

I'm a little bit new to all of these technologies so I'll try to be as clear as I can.
I'm writing a windows phone app that sends data in string format to a server:
public class sendDataControl
{
private string response = "";
public void sendToServer(string FullSTR)
{
try
{
WebClient webClient = new WebClient();
Uri uri = new Uri("http://pricequeryserver.azurewebsites.net/api/ReceiptDataService/?incomingdata=");
webClient.UploadStringAsync(uri,FullSTR);
webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(webClient_UploadStringCompleted);
}
catch (Exception ex)
...
...
}
}
void webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
if (e.Error != null)
{
responseXml=e.Error.Message;
MessageBox.Show(responseXml);
return;
}
else
{
responseXml = e.Result;
}
}
}
The server is an MVC4, basic, with api controller I added, that needs to get the data sent from the mobile.
As a test I'm just getting back a string that I send:
public class ReceiptDataServiceController : ApiController
{
private ReceiptContext db = new ReceiptContext();
...
...
public string GetDataFromMobile(string IncomingData)
{
return IncomingData;
}
}
While running the application I get an error via responseXml:
"The remote server returned an error: NotFound".
The server returns the right answer from all kinds of browsers, while on IIS and on the azure but not from the mobile emulator.
Any suggestions?
If you take a look at the documentation for UploadStringAsync overload you are using, you will notice that it sends data using POST method. While in your controller you have only implemented GET. And for your
You have to use other overload of UploadStringAsync, which lets you specify the HTTP VERB to use. And you must specify GET. Your client code should be converted to:
webClient.UploadStringAsync(uri,"GET", FullSTR);
And the best solution for simple GET operations like your is to actually use DownloadStringAsync:
var fullUri = new Uri("http://pricequeryserver.azurewebsites.net/api/ReceiptDataService/?incomingdata=" + FullStr);
webClient.DownloadStringAsync(fullUri);
Anyway, your question has nothing to do with Windows Azure, thus the removed tag.

Why does me use HttpClients.createDefault() as HttpClient singleton instance execute third request always hang

All ,
I create :
public static final HttpClient DEFAULT_HTTPCLIENT = HttpClients
.createDefault();
for(int i=0 ; i<5; i++){
DEFAULT_HTTPCLIENT.execute(requests[i]);
}
But when loop is to i =2 , that means just execute first two request , till third request , the client will hang and seems dead loop .
I refer some materials , I got may be caused by Http Thread Pool configuration limited . But I know what is standard solutions for this issue ? Since I want to send any request any times, but I don't want each time to create new HttpClient . So Do you have any good and standard suggestions for this issue ?
and After I debug this issue , I find it is block on HttpClient below codes : PoolingHttpClientConnectionManager -> leaseConnection ->
entry = future.get(timeout, tunit);
protected HttpClientConnection leaseConnection(
final Future<CPoolEntry> future,
final long timeout,
final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
final CPoolEntry entry;
try {
entry = future.get(timeout, tunit);
if (entry == null || future.isCancelled()) {
throw new InterruptedException();
}
Asserts.check(entry.getConnection() != null, "Pool entry with no connection");
if (this.log.isDebugEnabled()) {
this.log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
}
return CPoolProxy.newProxy(entry);
} catch (final TimeoutException ex) {
throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
}
}
That is because your code is leaking connections. By default HttpClient is configured to allow no more than two concurrent connections for the same route, hence it takes only two request executions before the pool is fully exhausted.
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e145

Resubmit web requests on resuming from dormancy

I am using RestSharp (a REST client for .NET) in my Windows Phone 8 app, but I think my question also applies using HttpWebRequest or any other ways of running web requests.
I am trying to find a way to automatically resubmit the requests when app is resumed from dormant state. This is only from dormant and not from the tombstone state.
The idea I had was to create a wrapper object which subscribes to the Deactivated event before starting the request and rerunning the request in case it received the event.
I assume that since the deactivated event was received, the request failed.
public class RestClientEx
{
bool wasDeactivated = false;
public async Task<T> ExecuteTaskAsync<T>(RestClient client, RestRequest request) where T : new()
{
var phoneApplicationService = App.Current.ApplicationLifetimeObjects.OfType<PhoneApplicationService>().First();
phoneApplicationService.Deactivated += phoneApplicationService_Deactivated;
var t = await client.ExecuteTaskAsync<T>(request);
if (this.wasDeactivated)
{
// resubmit request
this.wasDeactivated = false;
t = await this.ExecuteTaskAsync<T>(client, request);
}
return t;
}
void phoneApplicationService_Deactivated(object sender, DeactivatedEventArgs e)
{
(sender as PhoneApplicationService).Deactivated -= phoneApplicationService_Deactivated;
this.wasDeactivated = true;
}
}
My question is, is there another way to achieve this?
Is it OK what I am doing?