<html><head></head><body bgcolor="#FFFFFF"><div><span></span>Hi,</div><div><br><span>I would like to consider a change to the shovel plugin, to allow the shovel to failover more predictably against the list of broker endpoints in the rabbitmq_shovel configuration. &nbsp;Essentially, the idea is to try each endpoint in order of the declaration, and to use the first endpoint to which a connection can be made, instead of selecting an endpoint at random.</span><br><span></span><br><span>This does slightly violate the spirit of Erlang's "let it fail" philosophy, and I am not sure if the random endpoint selection in the current code is really more designed for clustered environments. &nbsp;Perhaps it would make more sense to make the iterative failover strategy an "opt-in" feature, if not simply for the sake of backwards-compatibility.</span><br><span></span><br><span>I am providing a patch, but not suggesting that this actual change go into production code, as I really did the change for testing purposes. &nbsp;I'm really more interested in whether others would find the patch useful, and whether there would be a way for us to fold a feature like this into the shovel. &nbsp;If there is interest, I would be happy to contribute something more production-worthy, for review.</span><br><span></span><br><span>Thanks,</span><br><span></span><br><span>-Fred</span><br><span></span><br><span>Here is the patch (based off 3.0.1 tag):</span><br><span></span><br><span># HG changeset patch</span><br><span># User Fred Dushin &lt;<a href="mailto:fred@dushin.net" x-apple-data-detectors="true" x-apple-data-detectors-result="0/0">fred@dushin.net</a>&gt;</span><br><span># Date&nbsp;<a href="tel:1366295416" x-apple-data-detectors="true" x-apple-data-detectors-result="0/1">1366295416</a>&nbsp;14400</span><br><span># Branch fdushin-failover</span><br><span># Node ID 0436511e18908fd8d38d5f56a1a3b0e5af807206</span><br><span># Parent &nbsp;cdf80b9ac08a61de718314baaff13f8ca5740c4c</span><br><span>Added changes to make failover to additional endpoints deterministic.</span><br><span></span><br><span>diff --git a/src/rabbit_shovel_worker.erl b/src/rabbit_shovel_worker.erl</span><br><span>--- a/src/rabbit_shovel_worker.erl</span><br><span>+++ b/src/rabbit_shovel_worker.erl</span><br><span>@@ -53,9 +53,9 @@</span><br><span>&nbsp;&nbsp;&nbsp;random:seed(A, B, C),</span><br><span>&nbsp;&nbsp;&nbsp;#shovel{sources = Sources, destinations = Destinations} = Config,</span><br><span>&nbsp;&nbsp;&nbsp;{InboundConn, InboundChan, InboundParams} =</span><br><span>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;make_conn_and_chan(Sources#endpoint.amqp_params),</span><br><span>+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;make_conn_and_chan(lists:reverse(Sources#endpoint.amqp_params)),</span><br><span>&nbsp;&nbsp;&nbsp;{OutboundConn, OutboundChan, OutboundParams} =</span><br><span>- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;make_conn_and_chan(Destinations#endpoint.amqp_params),</span><br><span>+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;make_conn_and_chan(lists:reverse(Destinations#endpoint.amqp_params)),</span><br><span></span><br><span>&nbsp;&nbsp;&nbsp;create_resources(InboundChan,</span><br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sources#endpoint.resource_declarations),</span><br><span>@@ -240,11 +240,27 @@</span><br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;amqp_channel:call(Chan, #'channel.flow'{active = Active}),</span><br><span>&nbsp;&nbsp;&nbsp;ok.</span><br><span></span><br><span>-make_conn_and_chan(AmqpParams) -&gt;</span><br><span>- &nbsp;&nbsp;&nbsp;AmqpParam = lists:nth(random:uniform(length(AmqpParams)), AmqpParams),</span><br><span>+amqp_params_to_string(#amqp_params_network{host=Host, port=Port, virtual_host=VirtualHost}) -&gt;</span><br><span>+ &nbsp;&nbsp;&nbsp;io_lib:format("Host: ~p Port: ~p VirtualHost: ~p", [Host, Port, VirtualHost]);</span><br><span>+amqp_params_to_string(#amqp_params_direct{virtual_host=VirtualHost}) -&gt;</span><br><span>+ &nbsp;&nbsp;&nbsp;io_lib:format("(Direct) Virtual Host: ~p", [VirtualHost]).</span><br><span>+</span><br><span>+make_conn_and_chan([]) -&gt;</span><br><span>+ &nbsp;&nbsp;&nbsp;throw(no_endpoints);</span><br><span>+make_conn_and_chan([AmqpParam|Rest]) -&gt;</span><br><span>+ &nbsp;&nbsp;&nbsp;try</span><br><span>+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get_conn_and_chan(AmqpParam)</span><br><span>+ &nbsp;&nbsp;&nbsp;catch</span><br><span>+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type:Reason -&gt;</span><br><span>+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error_logger:error_msg("Shovel failed to connect to ~s: ~p:~p", [amqp_params_to_string(AmqpParam), Type, Reason]),</span><br><span>+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;make_conn_and_chan(Rest)</span><br><span>+ &nbsp;&nbsp;&nbsp;end.</span><br><span>+</span><br><span>+get_conn_and_chan(AmqpParam) -&gt;</span><br><span>&nbsp;&nbsp;&nbsp;{ok, Conn} = amqp_connection:start(AmqpParam),</span><br><span>&nbsp;&nbsp;&nbsp;link(Conn),</span><br><span>&nbsp;&nbsp;&nbsp;{ok, Chan} = amqp_connection:open_channel(Conn),</span><br><span>+ &nbsp;&nbsp;&nbsp;error_logger:info_msg("Shovel connected to ~s.", [amqp_params_to_string(AmqpParam)]),</span><br><span>&nbsp;&nbsp;&nbsp;{Conn, Chan, AmqpParam}.</span><br><span></span><br><span>create_resources(Chan, Declarations) -&gt;</span><br><span></span><br></div><div><span></span></div></body></html>