|
2 | 2 | import copy
|
3 | 3 | import functools
|
4 | 4 | import logging
|
| 5 | +import select |
5 | 6 | import time
|
6 | 7 |
|
7 | 8 | import kafka.common
|
@@ -177,6 +178,10 @@ def _send_broker_aware_request(self, payloads, encoder_fn, decoder_fn):
|
177 | 178 | # For each broker, send the list of request payloads
|
178 | 179 | # and collect the responses and errors
|
179 | 180 | broker_failures = []
|
| 181 | + |
| 182 | + # For each KafkaConnection keep the real socket so that we can use |
| 183 | + # a select to perform unblocking I/O |
| 184 | + connections_by_socket = {} |
180 | 185 | for broker, payloads in payloads_by_broker.items():
|
181 | 186 | requestId = self._next_id()
|
182 | 187 | log.debug('Request %s to %s: %s', requestId, broker, payloads)
|
@@ -210,27 +215,34 @@ def _send_broker_aware_request(self, payloads, encoder_fn, decoder_fn):
|
210 | 215 | topic_partition = (payload.topic, payload.partition)
|
211 | 216 | responses[topic_partition] = None
|
212 | 217 | continue
|
| 218 | + else: |
| 219 | + connections_by_socket[conn.get_connected_socket()] = (conn, broker) |
213 | 220 |
|
214 |
| - try: |
215 |
| - response = conn.recv(requestId) |
216 |
| - except ConnectionError as e: |
217 |
| - broker_failures.append(broker) |
218 |
| - log.warning('ConnectionError attempting to receive a ' |
219 |
| - 'response to request %s from server %s: %s', |
220 |
| - requestId, broker, e) |
| 221 | + conn = None |
| 222 | + while connections_by_socket: |
| 223 | + sockets = connections_by_socket.keys() |
| 224 | + rlist, _, _ = select.select(sockets, [], [], None) |
| 225 | + conn, broker = connections_by_socket.pop(rlist[0]) |
| 226 | + try: |
| 227 | + response = conn.recv(requestId) |
| 228 | + except ConnectionError as e: |
| 229 | + broker_failures.append(broker) |
| 230 | + log.warning('ConnectionError attempting to receive a ' |
| 231 | + 'response to request %s from server %s: %s', |
| 232 | + requestId, broker, e) |
221 | 233 |
|
222 |
| - for payload in payloads: |
223 |
| - topic_partition = (payload.topic, payload.partition) |
224 |
| - responses[topic_partition] = FailedPayloadsError(payload) |
| 234 | + for payload in payloads_by_broker[broker]: |
| 235 | + topic_partition = (payload.topic, payload.partition) |
| 236 | + responses[topic_partition] = FailedPayloadsError(payload) |
225 | 237 |
|
226 |
| - else: |
227 |
| - _resps = [] |
228 |
| - for payload_response in decoder_fn(response): |
229 |
| - topic_partition = (payload_response.topic, |
230 |
| - payload_response.partition) |
231 |
| - responses[topic_partition] = payload_response |
232 |
| - _resps.append(payload_response) |
233 |
| - log.debug('Response %s: %s', requestId, _resps) |
| 238 | + else: |
| 239 | + _resps = [] |
| 240 | + for payload_response in decoder_fn(response): |
| 241 | + topic_partition = (payload_response.topic, |
| 242 | + payload_response.partition) |
| 243 | + responses[topic_partition] = payload_response |
| 244 | + _resps.append(payload_response) |
| 245 | + log.debug('Response %s: %s', requestId, _resps) |
234 | 246 |
|
235 | 247 | # Connection errors generally mean stale metadata
|
236 | 248 | # although sometimes it means incorrect api request
|
|
0 commit comments