This is an automated email from the ASF dual-hosted git repository.
CRZbulabula pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new eb9cc93284b fix: optimize reconnect exception as
`TTransport.TTransportException` (#18200)
eb9cc93284b is described below
commit eb9cc93284b0a7dc9c694d304b6389610b2007f5
Author: Zeyu Zhang <[email protected]>
AuthorDate: Thu Jul 16 13:59:12 2026 +0800
fix: optimize reconnect exception as `TTransport.TTransportException`
(#18200)
---
iotdb-client/client-py/iotdb/Session.py | 7 +-
.../tests/unit/test_session_connection.py | 116 +++++++++++++++++++++
2 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/iotdb-client/client-py/iotdb/Session.py
b/iotdb-client/client-py/iotdb/Session.py
index e4ed38ab228..b962e3ead5e 100644
--- a/iotdb-client/client-py/iotdb/Session.py
+++ b/iotdb-client/client-py/iotdb/Session.py
@@ -223,7 +223,7 @@ class Session(object):
self.__default_connection = self.init_connection(
self.__default_endpoint
)
- except Exception as e:
+ except IoTDBConnectionException as e:
if not self.reconnect():
if str(e).startswith("Could not connect to any of"):
error_msg = (
@@ -284,9 +284,12 @@ class Session(object):
session_id = open_resp.sessionId
statement_id = client.requestStatementId(session_id)
- except Exception as e:
+ except TTransport.TTransportException as e:
transport.close()
raise IoTDBConnectionException(e) from None
+ except Exception:
+ transport.close()
+ raise
if self.__zone_id is not None:
request = TSSetTimeZoneReq(session_id, self.__zone_id)
diff --git a/iotdb-client/client-py/tests/unit/test_session_connection.py
b/iotdb-client/client-py/tests/unit/test_session_connection.py
new file mode 100644
index 00000000000..7a78c697fea
--- /dev/null
+++ b/iotdb-client/client-py/tests/unit/test_session_connection.py
@@ -0,0 +1,116 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import importlib
+from types import SimpleNamespace
+
+import pytest
+from thrift.transport import TTransport
+
+from iotdb.thrift.common.ttypes import TSStatus
+from iotdb.utils.exception import StatementExecutionException
+
+
+class FakeSocket:
+ def setTimeout(self, timeout):
+ self.timeout = timeout
+
+
+class FakeTransport:
+ def __init__(self, socket):
+ self.socket = socket
+ self.opened = False
+
+ def isOpen(self):
+ return self.opened
+
+ def open(self):
+ self.opened = True
+
+ def close(self):
+ self.opened = False
+
+
[email protected](
+ "status_code,status_message",
+ [
+ (801, "Authentication failed."),
+ (822, "Account is blocked due to consecutive failed logins."),
+ ],
+)
+def test_session_does_not_retry_iotdb_status_error(
+ monkeypatch, status_code, status_message
+):
+ session_module = importlib.import_module("iotdb.Session")
+
+ class RejectingClient:
+ open_session_calls = 0
+
+ def __init__(self, protocol):
+ pass
+
+ def openSession(self, request):
+ RejectingClient.open_session_calls += 1
+ return SimpleNamespace(
+ status=TSStatus(code=status_code, message=status_message)
+ )
+
+ monkeypatch.setattr(
+ session_module.TSocket, "TSocket", lambda host, port: FakeSocket()
+ )
+ monkeypatch.setattr(session_module.TTransport, "TFramedTransport",
FakeTransport)
+ monkeypatch.setattr(session_module, "Client", RejectingClient)
+
+ session = session_module.Session.init_from_node_urls(
+ ["127.0.0.1:6667"], user="test", password="wrong"
+ )
+
+ with pytest.raises(StatementExecutionException) as exc_info:
+ session.open()
+
+ assert str(exc_info.value) == f"{status_code}: {status_message}"
+ assert RejectingClient.open_session_calls == 1
+
+
+def test_session_retries_transport_error(monkeypatch):
+ session_module = importlib.import_module("iotdb.Session")
+
+ class FailingClient:
+ open_session_calls = 0
+
+ def __init__(self, protocol):
+ pass
+
+ def openSession(self, request):
+ FailingClient.open_session_calls += 1
+ raise TTransport.TTransportException(message="Network is
unavailable.")
+
+ monkeypatch.setattr(
+ session_module.TSocket, "TSocket", lambda host, port: FakeSocket()
+ )
+ monkeypatch.setattr(session_module.TTransport, "TFramedTransport",
FakeTransport)
+ monkeypatch.setattr(session_module, "Client", FailingClient)
+
+ session = session_module.Session.init_from_node_urls(
+ ["127.0.0.1:6667"], user="test", password="wrong"
+ )
+
+ with pytest.raises(session_module.IoTDBConnectionException):
+ session.open()
+
+ assert FailingClient.open_session_calls == 1 + session.RETRY_NUM