https://github.com/elastic/elasticsearch/blob/099fb84cfcf87be6689c3516674f45438bafa767/server/src/main/java/org/elasticsearch/action/ActionListener.java#L420-L432

Rather than keeping hold of the `delegate` and using an `AtomicBoolean` to track the completion, we could use an `AtomicReference` and drop the whole listener on completion, which might free up heap in some fail-fast cases.
server/src/test/java/org/elasticsearch/action/ActionListenerTests.java
exReference.set(e);
                if (e instanceof IllegalArgumentException) {
                    throw (IllegalArgumentException) e;
                }
            }
        };
        ActionListener<Boolean> mapped = listener.map(b -> {
            if (b == null) {
                return null;
            } else if (b) {
                throw new IllegalStateException("simulate map function exception");
            } else {
                return b.toString();
            }
        });
        AssertionError assertionError = expectThrows(AssertionError.class, () -> mapped.onResponse(null));
        assertThat(assertionError.getCause().getCause(), instanceOf(IllegalArgumentException.class));
        assertNull(exReference.get());
        mapped.onResponse(false);
        assertNull(exReference.get());
        mapped.onResponse(true);
        assertThat(exReference.get(), instanceOf(IllegalStateException.class));
        assertionError = expectThrows(AssertionError.class, () -> mapped.onFailure(new IllegalArgumentException()));
        assertThat(assertionError.getCause().getCause(), instanceOf(IllegalArgumentException.class));
        assertThat(exReference.get(), instanceOf(IllegalArgumentException.class));
        mapped.onFailure(new IllegalStateException());
        assertThat(exReference.get(), instanceOf(IllegalStateException.class));
    }
}