Open mgoldsborough opened 7 years ago
Don't create the exchange each time you publish.
@postwait thanks for the reply.
As you suggested, I modified the code so it does not create the exchange each time. And this resolved the initial memory leak warning from node. I kept track of the listeners on the connection object and, when RMQ is running constantly, the listener count remains the same.
However, if the RMQ server is bounced, it looks like the listener count begins to creep upwards, albeit at a slower rate.
The code I ran and resulting output is below.
const EventEmitter = require('events'),
amqp = require('amqp');
let e = new EventEmitter();
let connectionOptions = {
url: 'amqp://guest:guest@127.0.0.1:5672'
};
let options = {
reconnect: true,
reconnectBackoffStrategy: 'linear',
reconnectExponentialLimit: 2000,
reconnectBackoffTime: 1000
};
let publishTimer = undefined;
let connection = amqp.createConnection(connectionOptions, options);
connection.on('error', (err) => {
console.error('Error connecting to AMQP broker (%s)', connectionOptions.url, err.message);
});
connection.on('close', () => {
console.error('Connection to AMQP broker (%s) closed', connectionOptions.url);
// Stop publishing
if(publishTimer) clearInterval(publishTimer);
// Disconnect the connection. I found that if I didn't do this,
// the connection would not automatically reconect.
connection.disconnect();
});
connection.on('connect', () => {
console.info('Connection made', connectionOptions.url);
});
connection.on('ready', () => {
console.info('Publisher connection made to AMQP', connectionOptions.url);
e.emit('connected');
});
// Open the exechange
e.on('connected', () => {
console.dir('got connected');
connection.exchange('', {confirm: true}, (exchange) => {
e.emit('opened', exchange);
});
});
// Once the exchange is opened, start interval to publish continously.
e.on('opened', (exchange) => {
publishTimer = setInterval(() => {
console.dir('Number of error listeners: ' + connection.listeners('error').length);
exchange.publish('telemetry', {abc: 123}, {}, (err) => {
if(err) {
console.error('Unable to publish message to queue', 'telemetry', err.message);
console.dir(err);
} else {
console.log('Published!');
}
});
}, 2000);
});
// Interval to keep process running
setInterval(() => {
console.log('Heartbeat');
}, 60000);
And here's the output. The comments (indicated by -->) in the file I added to help explain what was going on.
Connection made amqp://guest:guest@127.0.0.1:5672
Publisher connection made to AMQP amqp://guest:guest@127.0.0.1:5672
'got connected'
'got opened'
'Number of error listeners: 3'
Published!
'Number of error listeners: 3'
Published!
--> THE PREVIOUS 2 LINES REPEAT UNTIL RMQ IS STOPPED. NOTE, THE LISTENER COUNT STAYS CONSTANT
--> RMQ SERVER STOPPED
Publisher connection to AMQP broker (amqp://guest:guest@127.0.0.1:5672) closed
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) This socket has been ended by the other party
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) connect ECONNREFUSED 127.0.0.1:5672
Publisher connection to AMQP broker (amqp://guest:guest@127.0.0.1:5672) closed
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) write after end
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) connect ECONNREFUSED 127.0.0.1:5672
--> THE PREVIOUS 3 LINES ARE REPEATED UNTIL RMQ IS RESTARTED
--> RMQ SERVER RE-STARTED
Publisher connection made to AMQP amqp://guest:guest@127.0.0.1:5672
'got connected'
'got opened'
'Number of error listeners: 4'
Published!
'Number of error listeners: 4'
Published!
--> THE PREVIOUS 2 LINES REPEAT UNTIL RMQ IS STOPPED
--> NOTE THE INCREASE IN LISTENER COUNT FROM 3 TO 4
--> RMQ SERVER STOPPED
Publisher connection to AMQP broker (amqp://guest:guest@127.0.0.1:5672) closed
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) This socket has been ended by the other party
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) connect ECONNREFUSED 127.0.0.1:5672
Publisher connection to AMQP broker (amqp://guest:guest@127.0.0.1:5672) closed
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) write after end
Publisher error connecting to AMQP broker (amqp://guest:guest@127.0.0.1:5672) connect ECONNREFUSED 127.0.0.1:5672
--> THE PREVIOUS 3 LINES ARE REPEATED UNTIL RMQ IS RESTARTED
--> RMQ SERVER RE-STARTED
Publisher connection made to AMQP amqp://guest:guest@127.0.0.1:5672
'got connected'
'got opened'
'Number of error listeners: 5'
Published!
'Number of error listeners: 5'
Published!
I ran the test a lot longer and the listener count kept increasing until I ultimately got the same node.js warning, (node) warning: possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit.
.
Am I improperly handling connections/exchanges or is there a lower level bug in the reconnection logic as it pertains to handling event listeners?
Thanks.
having a similar issue.
I'm also facing the same issue.
Hello,
I have code which rapidly publishes data to an exchange. After a number of publishes, I'm getting an error indicating a memory leak inside the amqp library,
(node) warning: possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit.
.I found similar bugs on the issue tracker, but most were old (~2013) and none captured this exact scenario.
Here is example code which reproduces the bug:
The resulting output:
node version:
node-amqp version:
Any help would be much appreciated.