Continuing the conversation from
this question:
Two-part question here:
Can a TcpNetClientConnectionFactory
have multiple connections to its upstream
server, if the host and port are the same?
If so, how can I programmatically build a new connection for that connection
factory? I see the buildNewConnection
method, but it is protected.
The first connection is automatically built as soon as the first Message
passes through the factory. What we need to do is notice when following Messages
have a different ip_connectionId
, stand up a new connection, and route those
Messages to that new connection. Obviously, Messages with the original
ip_connectionId
would still be routed to the original connection.
Not sure whether it would be better to create multiple connections off of one
connection factory, or create a whole new connection factory, sending message
handler, and receiving channel adapter for each new connection.
If the inbound connection factory is a TcpNetServerConnectionFactory
, you can simply use a ThreadAffinityClientConnectionFactory
because each inbound connection gets its own thread.
You would call getConnection()
. This will bind the connection to the thread (and you can obtain the connection id from it), but you don't really need to map the header in this direction because of the thread affinity, you would only have to map on the return path.
Bear in mind, though, if the ThreadAffinityClientConnectionFactory
detects that a connection has been closed, it will create a new one. So, you might want to call getConnection()
in your mapper on each call. However, there would still be a race condition, so you might also need to listen for TcpConnectionCloseEvent
s and TcpConnectionOpenEvent
s.
If you use NIO on the inbound, or otherwise hand off the work to other threads via an executor, this won't work.
In that case you would need your own wrapping connection factory - you could use the ThreadAffinityClientConnectionFactory
as a model, but instead of storing the connections in a ThreadLocal
, you'd store them in a map. But you'd still need a ThreadLocal
(set upstream on each call) to tell the factory which connection to hand out when the adapter asks for one.
There's a trick you need to be aware of, however.
There is a property singleUse
on the connection factory. This serves 2 purposes;
- first, it tells the factory to create a new connection each time
getConnection()
is called instead of a single, shared, connection
- second, it tells the inbound adapter to close the connection after the reply is received
So the trick is you need singleUse=true
on the real factory (so it gives you a new connection each time getConnection()
is called), but singleUse=false
on the wrapping factory so the adapters don't close the connection.
I suggest you look at the ThreadAffinityClientConnectionFactory
and CachingClientConnectionFactory
connection factory to see how they work.
We should probably consider splitting this into two booleans; we could probably also make some improvements to avoid the need for a thread local by adding something like getConnection(String connectionId)
to the client factory contract and have the factory look up the connection internally; but that will require work in the adapters.
I'll capture an issue for this and see if we can get something in 5.2.
Rather a long answer, but I hope it makes sense.