Skip to content

channel.queueDelete sometimes throws NullPointerException, possibly due to race on recordedBindings #120

Closed
@spatula75

Description

@spatula75

When multiple channels share an AutorecoveringConnection and queues are coming and going from multiple theads, about 1 time out of 10000 , we are seeing a NullPointerException or ConcurrentModificationException to be thrown:

java.lang.NullPointerException
        at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.removeBindingsWithDestination(AutorecoveringConnection.java:768)
        at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.deleteRecordedQueue(AutorecoveringConnection.java:690)
        at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.deleteRecordedQueue(AutorecoveringChannel.java:562)
        at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.queueDelete(AutorecoveringChannel.java:303)
        at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.queueDelete(AutorecoveringChannel.java:299)

The code at this location looks innocuous enough:

    Set<RecordedBinding> removeBindingsWithDestination(String s) {
        Set<RecordedBinding> result = new HashSet<RecordedBinding>();
        for (Iterator<RecordedBinding> it = this.recordedBindings.iterator(); it.hasNext(); ) {
            RecordedBinding b = it.next();
            if(b.getDestination().equals(s)) { // [[ NPE here ]] //
                it.remove();
                result.add(b);
            }
        }
        return result;
    }

However, removeBindingsWithDestination is not synchronized, so it's possible for multiple threads to be in this method changing the recordedBindings ArrayList at the same time as bindings come and go from multiple threads, even with channels not being shared across threads (but the Connection is shared).

It looks the other accesses to recordedBindings are synchronized (though caution: maybeDeleteRecordedAutoDeleteExchange is synchronizing differently than the others) so removeBindingsWithDestination may have just fallen through the cracks.

It may be a sufficient fix just to make removeBindingsWithDestination synchronized.

(Another tangential thing I noticed is that most of the recorded maintenance is done from synchronized methods, but maybeDeleteRecordedAutoDeleteQueue during a basicCancel instead synchronizes on recordedQueues and consumers, and that this method just removes the recordedQueues entry, not the recordedBindings associated with the queue as well.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions