<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. 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. 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. 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. 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 <<a href="mailto:fred@dushin.net" x-apple-data-detectors="true" x-apple-data-detectors-result="0/0">fred@dushin.net</a>></span><br><span># Date <a href="tel:1366295416" x-apple-data-detectors="true" x-apple-data-detectors-result="0/1">1366295416</a> 14400</span><br><span># Branch fdushin-failover</span><br><span># Node ID 0436511e18908fd8d38d5f56a1a3b0e5af807206</span><br><span># Parent 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> random:seed(A, B, C),</span><br><span> #shovel{sources = Sources, destinations = Destinations} = Config,</span><br><span> {InboundConn, InboundChan, InboundParams} =</span><br><span>- make_conn_and_chan(Sources#endpoint.amqp_params),</span><br><span>+ make_conn_and_chan(lists:reverse(Sources#endpoint.amqp_params)),</span><br><span> {OutboundConn, OutboundChan, OutboundParams} =</span><br><span>- make_conn_and_chan(Destinations#endpoint.amqp_params),</span><br><span>+ make_conn_and_chan(lists:reverse(Destinations#endpoint.amqp_params)),</span><br><span></span><br><span> create_resources(InboundChan,</span><br><span> Sources#endpoint.resource_declarations),</span><br><span>@@ -240,11 +240,27 @@</span><br><span> amqp_channel:call(Chan, #'channel.flow'{active = Active}),</span><br><span> ok.</span><br><span></span><br><span>-make_conn_and_chan(AmqpParams) -></span><br><span>- 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}) -></span><br><span>+ 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}) -></span><br><span>+ io_lib:format("(Direct) Virtual Host: ~p", [VirtualHost]).</span><br><span>+</span><br><span>+make_conn_and_chan([]) -></span><br><span>+ throw(no_endpoints);</span><br><span>+make_conn_and_chan([AmqpParam|Rest]) -></span><br><span>+ try</span><br><span>+ get_conn_and_chan(AmqpParam)</span><br><span>+ catch</span><br><span>+ Type:Reason -></span><br><span>+ error_logger:error_msg("Shovel failed to connect to ~s: ~p:~p", [amqp_params_to_string(AmqpParam), Type, Reason]),</span><br><span>+ make_conn_and_chan(Rest)</span><br><span>+ end.</span><br><span>+</span><br><span>+get_conn_and_chan(AmqpParam) -></span><br><span> {ok, Conn} = amqp_connection:start(AmqpParam),</span><br><span> link(Conn),</span><br><span> {ok, Chan} = amqp_connection:open_channel(Conn),</span><br><span>+ error_logger:info_msg("Shovel connected to ~s.", [amqp_params_to_string(AmqpParam)]),</span><br><span> {Conn, Chan, AmqpParam}.</span><br><span></span><br><span>create_resources(Chan, Declarations) -></span><br><span></span><br></div><div><span></span></div></body></html>