Какой код будет восстанавливаться после **удаления соединения (время ожидания)**?

У меня есть gen_server в одной системе и 4 клиента в 4 других системах. Код работает, как и ожидалось, в течение 3 или 4 дней, когда gen_server сообщает «** Удаление соединения (время ожидания) **». Поскольку клиенты могут стать активными до или после запуска gen_server, клиенты выполняют этот код перед каждым вызовом gen_server:

connect_IPDB() ->
% try every 5 sec to connect to the server
case net_kernel:connect_node(?SERVER) of
    % When connected wait an additional 5 seconds for stablilty
    true -> timer:sleep(5000);
    false -> 
        timer:sleep(5000),
        connect_IPDB()
end.

Это работает, как и ожидалось, при запуске сервера или клиента в любом порядке. Все они подключаются и отображаются в узлах() при выполнении на сервере.

Вот в чем проблема. Через некоторое время после ошибки «** Удаление (тайм-аут) соединения **» nodes() показывает все узлы, подразумевая, что клиент не завис и выполнил приведенный выше код. Однако связь с узлом с истекшим временем ожидания не возобновилась. Как я могу восстановить соединение, не перезапуская клиент? Кстати, перезапуск клиента решает проблему.

Любая помощь, приветствуется.


person Bill Ott    schedule 06.08.2015    source источник
comment
Вся эта идея кажется мне странной, но в любом случае... Попробуйте, чтобы клиенты контролировали один из серверных процессов после того, как они подключились, и чтобы он вышел (сбой), когда он получил сообщение 'DOWN' от этого монитора.. Поместите клиент под супервизор, который перезапускает его в момент попытки подключения, как указано выше.   -  person zxq9    schedule 06.08.2015
comment
Спасибо за предложение. Кажется чрезмерно сложным. Итак, не мой первый выбор, но, возможно, мой единственный :-).   -  person Bill Ott    schedule 06.08.2015
comment
Если вы пишете на Erlang, это безусловно наименее сложное из всех решений. Erlang даже имеет стандартное поведение, построенное вокруг этого (называемое supervisor). Сказать ему, чтобы он управлял вашим клиентом, — это обычный способ работы. Вы можете написать своего супервайзера/менеджера в raw. Erlang вручную, чтобы понять, как все работает, если хотите, но использование супервизоров, предоставляемых OTP, требует значительно меньше кода (но немного чтения в первый раз).   -  person zxq9    schedule 06.08.2015
comment
Вы, наверное, правы. Это был мой первый опыт работы с супервайзерами и приложениями, использующими арматуру. Я был поражен тем, насколько хорошо это работало для того количества кода, которое я написал. Это почти похоже на ошибку или мою ошибку. Когда время ожидания узла истечет, будет ли команда node() на сервере показывать, что он больше не подключен? Если это так, то моя процедура connect() повторно подключает узел, но связь по-прежнему заблокирована. Если нет, то он работает по назначению, и моя процедура на самом деле не подключается по причинам, которые я не понимаю. Мне кажется, что использование супервизора для перезапуска игнорирует проблему.   -  person Bill Ott    schedule 06.08.2015


Ответы (1)


Я, наконец, понял проблему и решение. Мой тайм-аут был вызван тем, что рассматриваемые клиенты были приостановлены (это были виртуальные машины), чтобы их можно было зарезервировать. Поскольку они были приостановлены, когда они были возобновлены, супервизор в клиентах не видел никаких проблем, поэтому не перезапускал программу.

Исправление состояло в том, чтобы изменить connect_IPMD на:

connect_IPDB() ->
% See if we are connected to the server. Is the server in the list?
case lists:filter(fun(X) -> string:str(atom_to_list(X),atom_to_list(?SERVER))== 1 end, nodes(connected)) of
    % If empty, then not in list, enter the reconnect loop
    [] -> 
        connect_IPDB("Reconnect");
    % any thing else, then we are connected, so proceed
    _ -> ok 
end.
connect_IPDB(_Reconnect) ->
case net_kernel:connect_node(?SERVER) of
    % When connected wait an additional 5 seconds for stablilty
    true -> 
        timer:sleep(5000),
        Ips = gen_server:call({global, ?SERVER},getall_ips),
        % Re-initialize the iptables
        removechain(),
        createchain(),
        % Load the Ips into the local iptables f2bchain
        load_ips(Ips),
        % restart the ntpd 
        os:cmd("service ntpd restart");
    false -> 
        timer:sleep(5000),
        connect_IPDB("Reconnect")
end.

Это имеет дополнительное преимущество, заключающееся в сбросе часов клиента (перезапуске NTPD), когда клиент выходит из паузы.

Я оставляю супервайзера на месте, чтобы справиться с «настоящими» сбоями, а не с этим, вызванным самим собой.

person Bill Ott    schedule 11.08.2015