Skip to content

Commit ba2a3a9

Browse files
remove separate http client for telemetry
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
1 parent d9a4797 commit ba2a3a9

File tree

3 files changed

+26
-92
lines changed

3 files changed

+26
-92
lines changed

src/databricks/sql/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def read(self) -> Optional[OAuthToken]:
279279
host_url=server_hostname,
280280
http_path=http_path,
281281
port=kwargs.get("_port", 443),
282-
client_context=client_context,
282+
http_client=self.http_client,
283283
user_agent=self.session.useragent_header
284284
if hasattr(self, "session")
285285
else None,
@@ -301,7 +301,7 @@ def read(self) -> Optional[OAuthToken]:
301301
auth_provider=self.session.auth_provider,
302302
host_url=self.session.host,
303303
batch_size=self.telemetry_batch_size,
304-
client_context=client_context,
304+
http_client=self.http_client,
305305
)
306306

307307
self._telemetry_client = TelemetryClientFactory.get_telemetry_client(

src/databricks/sql/telemetry/telemetry_client.py

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -154,44 +154,6 @@ def _flush(self):
154154
pass
155155

156156

157-
class TelemetryHttpClientSingleton:
158-
"""
159-
Singleton HTTP client for telemetry operations.
160-
161-
This ensures that telemetry has its own dedicated HTTP client that
162-
is independent of individual connection lifecycles.
163-
"""
164-
165-
_instance = None
166-
_lock = threading.RLock()
167-
168-
def __new__(cls):
169-
if cls._instance is None:
170-
with cls._lock:
171-
if cls._instance is None:
172-
cls._instance = super().__new__(cls)
173-
cls._instance._http_client = None
174-
cls._instance._initialized = False
175-
return cls._instance
176-
177-
def get_http_client(self, client_context):
178-
"""Get or create the singleton HTTP client."""
179-
if not self._initialized and client_context:
180-
with self._lock:
181-
if not self._initialized:
182-
self._http_client = UnifiedHttpClient(client_context)
183-
self._initialized = True
184-
return self._http_client
185-
186-
def close(self):
187-
"""Close the singleton HTTP client."""
188-
with self._lock:
189-
if self._http_client:
190-
self._http_client.close()
191-
self._http_client = None
192-
self._initialized = False
193-
194-
195157
class TelemetryClient(BaseTelemetryClient):
196158
"""
197159
Telemetry client class that handles sending telemetry events in batches to the server.
@@ -210,7 +172,7 @@ def __init__(
210172
host_url,
211173
executor,
212174
batch_size,
213-
client_context,
175+
http_client,
214176
):
215177
logger.debug("Initializing TelemetryClient for connection: %s", session_id_hex)
216178
self._telemetry_enabled = telemetry_enabled
@@ -224,9 +186,8 @@ def __init__(
224186
self._host_url = host_url
225187
self._executor = executor
226188

227-
# Use singleton HTTP client for telemetry instead of connection-specific client
228-
self._http_client_singleton = TelemetryHttpClientSingleton()
229-
self._http_client = self._http_client_singleton.get_http_client(client_context)
189+
# Use the provided HTTP client directly
190+
self._http_client = http_client
230191

231192
def _export_event(self, event):
232193
"""Add an event to the batch queue and flush if batch is full"""
@@ -503,7 +464,7 @@ def initialize_telemetry_client(
503464
auth_provider,
504465
host_url,
505466
batch_size,
506-
client_context,
467+
http_client,
507468
):
508469
"""Initialize a telemetry client for a specific connection if telemetry is enabled"""
509470
try:
@@ -526,7 +487,7 @@ def initialize_telemetry_client(
526487
host_url=host_url,
527488
executor=TelemetryClientFactory._executor,
528489
batch_size=batch_size,
529-
client_context=client_context,
490+
http_client=http_client,
530491
)
531492
else:
532493
TelemetryClientFactory._clients[
@@ -579,10 +540,10 @@ def connection_failure_log(
579540
host_url: str,
580541
http_path: str,
581542
port: int,
582-
client_context,
543+
http_client,
583544
user_agent: Optional[str] = None,
584545
):
585-
"""Send error telemetry when connection creation fails, without requiring a session"""
546+
"""Send error telemetry when connection creation fails, using existing HTTP client"""
586547

587548
UNAUTH_DUMMY_SESSION_ID = "unauth_session_id"
588549

@@ -592,7 +553,7 @@ def connection_failure_log(
592553
auth_provider=None,
593554
host_url=host_url,
594555
batch_size=TelemetryClientFactory.DEFAULT_BATCH_SIZE,
595-
client_context=client_context,
556+
http_client=http_client,
596557
)
597558

598559
telemetry_client = TelemetryClientFactory.get_telemetry_client(

tests/unit/test_telemetry.py

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,12 @@
1919

2020

2121
@pytest.fixture
22-
@patch("databricks.sql.telemetry.telemetry_client.TelemetryHttpClientSingleton")
23-
def mock_telemetry_client(mock_singleton_class):
22+
def mock_telemetry_client():
2423
"""Create a mock telemetry client for testing."""
2524
session_id = str(uuid.uuid4())
2625
auth_provider = AccessTokenAuthProvider("test-token")
2726
executor = MagicMock()
28-
mock_client_context = MagicMock()
29-
30-
# Mock the singleton to return a mock HTTP client
31-
mock_singleton = mock_singleton_class.return_value
32-
mock_singleton.get_http_client.return_value = MagicMock()
27+
mock_http_client = MagicMock()
3328

3429
return TelemetryClient(
3530
telemetry_enabled=True,
@@ -38,7 +33,7 @@ def mock_telemetry_client(mock_singleton_class):
3833
host_url="test-host.com",
3934
executor=executor,
4035
batch_size=TelemetryClientFactory.DEFAULT_BATCH_SIZE,
41-
client_context=mock_client_context,
36+
http_client=mock_http_client,
4237
)
4338

4439

@@ -217,16 +212,11 @@ def telemetry_system_reset(self):
217212
TelemetryClientFactory._executor = None
218213
TelemetryClientFactory._initialized = False
219214

220-
@patch("databricks.sql.telemetry.telemetry_client.TelemetryHttpClientSingleton")
221-
def test_client_lifecycle_flow(self, mock_singleton_class):
215+
def test_client_lifecycle_flow(self):
222216
"""Test complete client lifecycle: initialize -> use -> close."""
223217
session_id_hex = "test-session"
224218
auth_provider = AccessTokenAuthProvider("token")
225-
mock_client_context = MagicMock()
226-
227-
# Mock the singleton to return a mock HTTP client
228-
mock_singleton = mock_singleton_class.return_value
229-
mock_singleton.get_http_client.return_value = MagicMock()
219+
mock_http_client = MagicMock()
230220

231221
# Initialize enabled client
232222
TelemetryClientFactory.initialize_telemetry_client(
@@ -235,7 +225,7 @@ def test_client_lifecycle_flow(self, mock_singleton_class):
235225
auth_provider=auth_provider,
236226
host_url="test-host.com",
237227
batch_size=TelemetryClientFactory.DEFAULT_BATCH_SIZE,
238-
client_context=mock_client_context,
228+
http_client=mock_http_client,
239229
)
240230

241231
client = TelemetryClientFactory.get_telemetry_client(session_id_hex)
@@ -248,40 +238,28 @@ def test_client_lifecycle_flow(self, mock_singleton_class):
248238
mock_close.assert_called_once()
249239

250240
# Should get NoopTelemetryClient after close
251-
client = TelemetryClientFactory.get_telemetry_client(session_id_hex)
252-
assert isinstance(client, NoopTelemetryClient)
253241

254-
@patch("databricks.sql.telemetry.telemetry_client.TelemetryHttpClientSingleton")
255-
def test_disabled_telemetry_flow(self, mock_singleton_class):
256-
"""Test that disabled telemetry uses NoopTelemetryClient."""
242+
def test_disabled_telemetry_creates_noop_client(self):
243+
"""Test that disabled telemetry creates NoopTelemetryClient."""
257244
session_id_hex = "test-session"
258-
mock_client_context = MagicMock()
259-
260-
# Mock the singleton to return a mock HTTP client
261-
mock_singleton = mock_singleton_class.return_value
262-
mock_singleton.get_http_client.return_value = MagicMock()
245+
mock_http_client = MagicMock()
263246

264247
TelemetryClientFactory.initialize_telemetry_client(
265248
telemetry_enabled=False,
266249
session_id_hex=session_id_hex,
267250
auth_provider=None,
268251
host_url="test-host.com",
269252
batch_size=TelemetryClientFactory.DEFAULT_BATCH_SIZE,
270-
client_context=mock_client_context,
253+
http_client=mock_http_client,
271254
)
272255

273256
client = TelemetryClientFactory.get_telemetry_client(session_id_hex)
274257
assert isinstance(client, NoopTelemetryClient)
275258

276-
@patch("databricks.sql.telemetry.telemetry_client.TelemetryHttpClientSingleton")
277-
def test_factory_error_handling(self, mock_singleton_class):
259+
def test_factory_error_handling(self):
278260
"""Test that factory errors fall back to NoopTelemetryClient."""
279261
session_id = "test-session"
280-
mock_client_context = MagicMock()
281-
282-
# Mock the singleton to return a mock HTTP client
283-
mock_singleton = mock_singleton_class.return_value
284-
mock_singleton.get_http_client.return_value = MagicMock()
262+
mock_http_client = MagicMock()
285263

286264
# Simulate initialization error
287265
with patch(
@@ -294,23 +272,18 @@ def test_factory_error_handling(self, mock_singleton_class):
294272
auth_provider=AccessTokenAuthProvider("token"),
295273
host_url="test-host.com",
296274
batch_size=TelemetryClientFactory.DEFAULT_BATCH_SIZE,
297-
client_context=mock_client_context,
275+
http_client=mock_http_client,
298276
)
299277

300278
# Should fall back to NoopTelemetryClient
301279
client = TelemetryClientFactory.get_telemetry_client(session_id)
302280
assert isinstance(client, NoopTelemetryClient)
303281

304-
@patch("databricks.sql.telemetry.telemetry_client.TelemetryHttpClientSingleton")
305-
def test_factory_shutdown_flow(self, mock_singleton_class):
282+
def test_factory_shutdown_flow(self):
306283
"""Test factory shutdown when last client is removed."""
307284
session1 = "session-1"
308285
session2 = "session-2"
309-
mock_client_context = MagicMock()
310-
311-
# Mock the singleton to return a mock HTTP client
312-
mock_singleton = mock_singleton_class.return_value
313-
mock_singleton.get_http_client.return_value = MagicMock()
286+
mock_http_client = MagicMock()
314287

315288
# Initialize multiple clients
316289
for session in [session1, session2]:
@@ -320,7 +293,7 @@ def test_factory_shutdown_flow(self, mock_singleton_class):
320293
auth_provider=AccessTokenAuthProvider("token"),
321294
host_url="test-host.com",
322295
batch_size=TelemetryClientFactory.DEFAULT_BATCH_SIZE,
323-
client_context=mock_client_context,
296+
http_client=mock_http_client,
324297
)
325298

326299
# Factory should be initialized

0 commit comments

Comments
 (0)