[Bug] notifyMasterOnline aborts the long-polling wake-up with a NullPointerException when an arrival drains a bucket first
Los mantenedores suelen responder en 1 día
@iloveeyjafjalla ya está trabajando en esto.
Desde el 14/10/2026.
- #11442 de @iloveeyjafjalla — abierto
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 82/100
Línea de trabajo
Empieza en PullRequestHoldService.notifyMasterOnline, alrededor de la línea 191, donde el bucle sobre pullRequestTable llama a mpr.cloneListAndClear() e itera el resultado directamente. Lee ManyPullRequest.cloneListAndClear(), que devuelve null para un bucket vacío, y compáralo con la comprobación de null en notifyMessageArriving. Está terminado cuando un bucket que se vacía de forma concurrente se omite y el barrido sigue despertando las peticiones de las otras colas.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Describe the Bug
When the smallest broker of a group changes and this broker becomes the master, BrokerController#onMinBrokerChange ends with pullRequestHoldService.notifyMasterOnline(), whose job is to immediately re-execute every pull request that is currently suspended, so that clients do not have to wait for their own suspend timeout after a master comes online.
That sweep assumes a bucket it has just seen as non-empty still holds requests when it drains it:
for (ManyPullRequest mpr : this.pullRequestTable.values()) {
if (mpr == null || mpr.isEmpty()) {
continue;
}
for (PullRequest request : mpr.cloneListAndClear()) {
ManyPullRequest#cloneListAndClear() returns null (not an empty list) whenever the bucket is empty at drain time:
public synchronized List<PullRequest> cloneListAndClear() {
if (!this.pullRequestList.isEmpty()) {
...
return result;
}
return null;
}
The buckets are drained by the message-arrival path on the store's dispatch thread (NotifyMessageArrivingListener -> PullRequestHoldService#notifyMessageArriving, which drains the same bucket and replays the requests that did not match). An arrival that wins the race between the isEmpty() check above and the drain makes the loop iterable null, so the enhanced for throws a NullPointerException.
Impact
- The
NullPointerExceptionescapesnotifyMasterOnline()intoonMinBrokerChange. The sweep is over, so every bucket that had not yet been visited keeps its requests suspended: those clients sit out their full suspend timeout instead of being woken immediately - exactly the stall this method exists to prevent, and in exactly the failover window it is meant for. - The exception is thrown on the thread that updates the min-broker state (including the
UPDATE_MIN_BROKERadmin path), so the caller sees a failure for an operation that has otherwise already been applied.
The same class shows what the intended contract is: notifyMessageArriving drains a bucket the same way and guards the result with if (requestList != null) before iterating, so the missing guard in notifyMasterOnline is an oversight rather than a documented behaviour.
How to Reproduce
- Suspend a pull request on some
topic@queueId(long polling enabled, i.e. the client sent the suspend flag and the pull returnedPULL_NOT_FOUNDlonger than the max. offset). - Produce a message for that queue from another thread, so the dispatch thread drains the same bucket through
notifyMessageArrivingin the same instant asnotifyMasterOnline(). - The stricter, deterministic form of the race: the bucket reports itself as non-empty and is drained before
notifyMasterOnline()drains it, which is what makes the sweep iterablenull. - Result with the current code:
java.lang.NullPointerException at org.apache.rocketmq.broker.longpolling.PullRequestHoldService.notifyMasterOnline(PullRequestHoldService.java:191), and the remaining buckets are not woken.
Expected Behavior
A bucket that lost that race is skipped; the sweep continues and still wakes the requests held for the other queues.
Proposed Fix
Read the drained list into a local variable and skip the bucket when it answers null, instead of iterating the call result directly:
List<PullRequest> requestList = mpr.cloneListAndClear();
if (requestList == null) {
continue;
}
for (PullRequest request : requestList) {
Environment
- 5.5.1-SNAPSHOT (
develop, 0dd48c39db), all platforms
- Lenguaje dominante
- Java
- Estrellas
- 22.6k
- Forks
- 12k
- Merge medio
- 6 d 21 h
- PR fusionados (30 d)
- 17
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/rocketmq
-
[Bug] DefaultMQPushConsumer.shutdown() never stops the pop consume service, so its non-daemon threads keep the JVM alivePosiblemente ocupada @iloveeyjafjalla la tomó hace 1 día. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
apache/rocketmq#11427 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
[Enhancement] FilterFactory duplicate-registration and unregister semantics lack testsPosiblemente ocupada @chennaji9 la tomó hace 5 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
apache/rocketmq#11340 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
[Enhancement] LogicExpression three-valued truth table and short-circuit behavior lack direct testsPosiblemente ocupada @chennaji9 la tomó hace 5 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
apache/rocketmq#11339 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
[Enhancement] SyncStateInfo defensive-copy and epoch semantics lack direct testsPosiblemente ocupada @chennaji9 la tomó hace 5 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
apache/rocketmq#11338 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
[Enhancement] ControllerClosure request-completion semantics lack direct testsPosiblemente ocupada @chennaji9 la tomó hace 5 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
apache/rocketmq#11337 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de apache/rocketmq
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
bug new windows
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día
-
iOS podspec depends on `React-Codegen`, which resolves to an unrelated pod on CocoaPods trunkAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
GantMan/jail-monkey#380 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
objectionary/jucs#145 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
objectionary/lints#1559 ·
Los mantenedores suelen responder en 2 días