Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c0ef8fe

Browse files
authored
Retry Py4J on empty response (#551)
This PR retries Py4J on empty response. The other end might not be dead but the JVM itself might keep running. In this case, new connection has to be made.
1 parent ccd7aa3 commit c0ef8fe

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed

py4j-python/src/py4j/clientserver.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,8 @@ def send_command(self, command):
537537
# Happens when a the other end is dead. There might be an empty
538538
# answer before the socket raises an error.
539539
if answer.strip() == "":
540-
raise Py4JNetworkError("Answer from Java side is empty")
540+
raise Py4JNetworkError(
541+
"Answer from Java side is empty", when=proto.EMPTY_RESPONSE)
541542
if answer.startswith(proto.RETURN_MESSAGE):
542543
return answer[1:]
543544
else:
@@ -560,6 +561,8 @@ def send_command(self, command):
560561
proto.ERROR_RETURN_MESSAGE.encode("utf-8"))
561562
except Exception as e:
562563
logger.info("Error while receiving.", exc_info=True)
564+
if isinstance(e, Py4JNetworkError) and e.when == proto.EMPTY_RESPONSE:
565+
raise
563566
raise Py4JNetworkError(
564567
"Error while sending or receiving", e, proto.ERROR_ON_RECEIVE)
565568

py4j-python/src/py4j/java_gateway.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,8 +1049,12 @@ def send_command(self, command, retry=True, binary=False):
10491049
reset = True
10501050
connection.close(reset)
10511051
if self._should_retry(retry, connection, pne):
1052+
if pne.when == proto.ERROR_ON_SEND or pne.when == proto.EMPTY_RESPONSE:
1053+
# For empty response, just try once more because now we reset
1054+
# the connection, and should work if the other end is alive.
1055+
retry = False
10521056
logging.info("Exception while sending command.", exc_info=True)
1053-
response = self.send_command(command, binary=binary)
1057+
response = self.send_command(command, retry, binary=binary)
10541058
else:
10551059
logging.exception(
10561060
"Exception while sending command.")
@@ -1107,7 +1111,8 @@ def _create_connection_guard(self, connection):
11071111
return GatewayConnectionGuard(self, connection)
11081112

11091113
def _should_retry(self, retry, connection, pne=None):
1110-
return pne and pne.when == proto.ERROR_ON_SEND
1114+
return retry and pne and (
1115+
pne.when == proto.ERROR_ON_SEND or pne.when == proto.EMPTY_RESPONSE)
11111116

11121117
def close(self):
11131118
"""Closes all currently opened connections.
@@ -1254,10 +1259,12 @@ def send_command(self, command):
12541259
# Happens when a the other end is dead. There might be an empty
12551260
# answer before the socket raises an error.
12561261
if answer.strip() == "":
1257-
raise Py4JNetworkError("Answer from Java side is empty")
1262+
raise Py4JNetworkError("Answer from Java side is empty", when=proto.EMPTY_RESPONSE)
12581263
return answer
12591264
except Exception as e:
12601265
logger.info("Error while receiving.", exc_info=True)
1266+
if isinstance(e, Py4JNetworkError) and e.when == proto.EMPTY_RESPONSE:
1267+
raise
12611268
raise Py4JNetworkError(
12621269
"Error while receiving", e, proto.ERROR_ON_RECEIVE)
12631270

py4j-python/src/py4j/protocol.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@
172172
# ERRORS
173173
ERROR_ON_SEND = "on_send"
174174
ERROR_ON_RECEIVE = "on_receive"
175+
EMPTY_RESPONSE = "empty_response"
175176

176177

177178
def escape_new_line(original):

0 commit comments

Comments
 (0)