Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache Camel: why is TCP connection not closed after receiving 200 OK

We are using Apache Camel as an orchestration engine. Typically, the following scenario:

client sends HTTP request <-> CAMEL code <-> external server(s)

The ball starts to roll when our client sends a HTTP request to our CAMEL code. The Camel code will trigger external servers via REST HTTP calls. Eventually, the Camel code will send a reply back to the client.

The last action before sending the response back to the client, the Camel code sends a HTTP GET towards an external server. So a TCP connection is setup first, then the data sent. After some time (this might take up 5 to 10 seconds), the external server replies with a 200 OK.

Problem: Camel does not send a TCP FIN to the external server after receiving the 200 OK. As a result, the TCP connection remains open ... (the external server then closes the TCP connection itself after a timeout of 200 seconds, but this means a TCP resource lost during 200 seconds).

So, at TCP level, it goes like this:

Camel <----------> external server

   TCP SYN  -->
   <-- TCP SYN,ACK
   TCP ACK  -->

   HTTP GET -->
   <-- 200 OK
   TCP ACK  -->

   <200 seconds later>
   <-- TCP FIN,ACK
   TCP ACK  -->

Any idea how I can have Camel close the TCP connection after it has received the 200 OK ?

Note: I tried adding the "Connection: close" header, but Camel did not add the header ?! It seemed to ignore it ...

This was the code to add the header:

exchange.getOut().setHeader("Connection","Close");

I am using Camel 2.9.1 in a Spring framework with Eclipse IDE.

like image 807
opstalj Avatar asked May 29 '12 11:05

opstalj


2 Answers

Unfortunately, I did not see another solution than create a custom HttpHeaderFilterStrategy class which does not filter out the Connection header. Then before sending out my request to the external server, I am setting the header "Connection: close". As soon as this request gets replied, the Camel code then sends a TCP FIN, ACK in order to close the TCP connection.

More details:

1) create a custom HttpHeaderFilterStrategy class, eg: CustomHttpHeaderFilterStrategy

2) adapt the applicationContext.xml so it points to that class, eg:

<bean id="http" class="org.apache.camel.component.http.HttpComponent">
    <property name="camelContext" ref="camel"/>
    <property name="headerFilterStrategy" ref="myHeaderFilterStrategy"/>
</bean>

<bean id="myHeaderFilterStrategy" class="com.alu.iptc.com.CustomHttpHeaderFilterStrategy">
</bean>

3) adapt your code, so that the Connection: close header is set, eg:

exchange.getOut().setHeader("Connection","close");
like image 124
opstalj Avatar answered Oct 19 '22 20:10

opstalj


HTTP1.1 connections are to be considered to be kept alive after the first message for a while to allow multiple files to be delivered in one TCP session for performance reasons. Normlly, a http server might cut connections after a few seconds to save threads while allow multiple files to be downloaded. The Camel http component will probably behave the same way. http://en.wikipedia.org/wiki/HTTP_persistent_connection

The official HTTP client which Camel relies on can be configured to use or not use persistent connections, but default is true: http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html

Although I have not tried it, it should be possible to set a system property to configure this

http.keepAlive=<boolean>

You should be able to set it on the camel context if you want

<camelContext>
   <properties>
       <property key="http.keepAlive" value="false"/>
  </properties> 
</camelContext>

Note that I have not tried it. If you make it work, it would be nice to hear the results!

like image 2
Petter Nordlander Avatar answered Oct 19 '22 22:10

Petter Nordlander