-
Notifications
You must be signed in to change notification settings - Fork 626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@Transactional with RabbitTemplate.sendConnectionFactorySelectorExpression + SimpleRoutingConnectionFactory #1357
Comments
Can you provide more information? Or, preferably, a MCRE. I see Then, in Where are you seeing This test passes: @Test
@SuppressWarnings("unchecked")
public void testRoutingConnectionFactoryWithTx() throws Exception {
org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory1 = Mockito
.mock(org.springframework.amqp.rabbit.connection.ConnectionFactory.class);
org.springframework.amqp.rabbit.connection.Connection connection1
= mock(org.springframework.amqp.rabbit.connection.Connection.class);
Channel channel1 = mock(Channel.class, "channel1");
given(channel1.isOpen()).willReturn(true);
willReturn(connection1).given(connectionFactory1).createConnection();
given(connection1.isOpen()).willReturn(true);
given(connection1.createChannel(true)).willReturn(channel1);
org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory2 = Mockito
.mock(org.springframework.amqp.rabbit.connection.ConnectionFactory.class);
org.springframework.amqp.rabbit.connection.Connection connection2
= mock(org.springframework.amqp.rabbit.connection.Connection.class);
Channel channel2 = mock(Channel.class, "channel1");
given(channel2.isOpen()).willReturn(true);
willReturn(connection2).given(connectionFactory1).createConnection();
given(connection2.isOpen()).willReturn(true);
given(connection2.createChannel(true)).willReturn(channel2);
Map<Object, org.springframework.amqp.rabbit.connection.ConnectionFactory> factories =
new HashMap<Object, org.springframework.amqp.rabbit.connection.ConnectionFactory>(2);
factories.put("foo", connectionFactory1);
factories.put("bar", connectionFactory2);
AbstractRoutingConnectionFactory connectionFactory = new SimpleRoutingConnectionFactory();
connectionFactory.setTargetConnectionFactories(factories);
connectionFactory.setDefaultTargetConnectionFactory(connectionFactory2);
final RabbitTemplate template = new RabbitTemplate(connectionFactory);
Expression expression = new SpelExpressionParser()
.parseExpression("'foo'");
template.setSendConnectionFactorySelectorExpression(expression);
template.setChannelTransacted(true);
new TransactionTemplate(new TestTransactionManager()).execute(status -> {
template.convertAndSend("foo", "bar", "baz");
return null;
});
Mockito.verify(connectionFactory1, times(1)).createConnection();
Mockito.verify(connectionFactory2, never()).createConnection();
} |
Aha - it does fail, if I use a new TransactionTemplate(new RabbitTransactionManager(connectionFactory)).execute(status -> {
template.convertAndSend("foo", "bar", "baz");
return null;
}); |
OK, thank you, or need any more detail? |
Looking at it now... will let you know. |
The issue is that when using the Is there some reason that you must use a |
OK, hint from me, but am not really sure if I am missing something or not
protected boolean isChannelLocallyTransacted(Channel channel) {
return isChannelTransacted() && !ConnectionFactoryUtils.isChannelTransactional(channel, getConnectionFactory());
} and I think in that place it will not find correct object in some transaction holder object |
I woulnt say I am using that, we using default/autoconfigured manager |
I used so edit our code to use |
Yes, because then the transaction manager will get the right factory. It's a limitation of using the expression with the template; it won't work if the TM creates the connection. We should document that limitation - there is no way for the TM to know anything about the template's configuration. That said, I don't see Boot auto-configuring a |
This code is correct: return isChannelTransacted() && !ConnectionFactoryUtils.isChannelTransactional(channel, getConnectionFactory()); Because the key to the resource is the routing CF, not one of its delegates. If we looked up the delegate there, we would never find an existing transaction. |
not needed anymore, thank you for clarification and your time! |
Bug report
I am experiecing weird behavior when using SimpleRoutingConnectionFactory together with RabbitTemplate with filled
sendConnectionFactorySelectorExpression
. Then usage with@Transactional
method, message has been sent immediately just like without any open transactionI am using this construct for publishing instead of
SimpleResourceHolder.bind
Imo it is caused in RabbitTemplate, when creating channel - method
obtainTargetConnectionFactory
is used to obtain connection (this method takes into accountsendConnectionFactorySelectorExpression
) but then, when "transaction" context is evaluated, simple gettergetConnectionFactory
is usedThe text was updated successfully, but these errors were encountered: