Skip to content
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

Dangling connections on socket timeout #326

Closed
ArenSH opened this issue Feb 9, 2017 · 2 comments
Closed

Dangling connections on socket timeout #326

ArenSH opened this issue Feb 9, 2017 · 2 comments

Comments

@ArenSH
Copy link

ArenSH commented Feb 9, 2017

Hi,

There is an issue with socket timeout: on some network conditions we may get dangling connections.

Assume we had some problem in network such as rabbitMQ server can see client but client cannot get packages from server. Our client tried to recreate connection that closed due to heartbeat error and after 2 attempts connection was reestablished. But rabbitMQ server keeps resending packages for our previous attempts so we now have three connections: one that client use, and two dangling for previous attempts. And that connection have no error listener so any error will crash our client app.

Basically, any condition that cause tcp to resend "opening" packages will cause dangling connections.

Steps to reproduce:

  1. Setup rabbitMQ server in docker docker run -d rabbitmq:latest
  2. get ip of container docker inspect -f '{{ .NetworkSettings.IPAddress }} <container_id>
  3. Emulate network error to get socket timeout sudo iptables -I INPUT -s <container_ip> -j DROP
  4. Run test script below
  5. Wait for several connection attempts, then recover network sudo iptables -D INPUT -s <container_ip> -j DROP
  6. Now we have multiple connections to server and only one of them are available to us.

This lead to various unhadled errors (Heartbeat timeout, ECONNRESET, etc.)

This issue can be fixed by calling connection.toClosed on socket timeout, but i'm not shure if its correct way (lib/connect.js):

sock.setTimeout(timeout, function() {
    var error = new Error('connect ETIMEDOUT');
    if (c) c.toClosed(error);
    openCallback(error);
});

Please, take a look at this issue and let me know if pull request is required.

Test script:

'use strict';

const amqp = require('amqplib');

function openConnection() {
    amqp.connect('amqp://<container_ip>:<container_port>?heartbeat=5', {timeout: 7000})
        .then(function(con) {
            console.log('Open connection');
            con.on('close', openConnection);
            con.on('error', function(err) { console.log(err.message); });
        })
        .catch(function(err) {
            console.log(err.message);
            openConnection();
        });
    }

openConnection();
@squaremo
Copy link
Collaborator

This is a subtle issue, thank you for the detailed report.

This issue can be fixed by calling connection.toClosed on socket timeout, but i'm not shure if its correct way (lib/connect.js):

toClosed goes through the whole AMQP closing handshake, which I don't think is required, since we have not competed the opening handshake at that point. I think closing the TCP socket (sock.end() and sock.destroy()) should be enough.

ArenSH pushed a commit to ArenSH/amqp.node that referenced this issue Mar 20, 2017
@ArenSH
Copy link
Author

ArenSH commented Mar 23, 2017

@squaremo Could you please tell when will this fix land in npm package?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants