Skip to content

Commit 1e6648d

Browse files
committed
[SPARK-12617][PYSPARK] Move Py4jCallbackConnectionCleaner to Streaming
Move Py4jCallbackConnectionCleaner to Streaming because the callback server starts only in StreamingContext. Author: Shixiong Zhu <[email protected]> Closes apache#10621 from zsxwing/SPARK-12617-2.
1 parent f82ebb1 commit 1e6648d

File tree

2 files changed

+63
-61
lines changed

2 files changed

+63
-61
lines changed

python/pyspark/context.py

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -54,64 +54,6 @@
5454
}
5555

5656

57-
class Py4jCallbackConnectionCleaner(object):
58-
59-
"""
60-
A cleaner to clean up callback connections that are not closed by Py4j. See SPARK-12617.
61-
It will scan all callback connections every 30 seconds and close the dead connections.
62-
"""
63-
64-
def __init__(self, gateway):
65-
self._gateway = gateway
66-
self._stopped = False
67-
self._timer = None
68-
self._lock = RLock()
69-
70-
def start(self):
71-
if self._stopped:
72-
return
73-
74-
def clean_closed_connections():
75-
from py4j.java_gateway import quiet_close, quiet_shutdown
76-
77-
callback_server = self._gateway._callback_server
78-
with callback_server.lock:
79-
try:
80-
closed_connections = []
81-
for connection in callback_server.connections:
82-
if not connection.isAlive():
83-
quiet_close(connection.input)
84-
quiet_shutdown(connection.socket)
85-
quiet_close(connection.socket)
86-
closed_connections.append(connection)
87-
88-
for closed_connection in closed_connections:
89-
callback_server.connections.remove(closed_connection)
90-
except Exception:
91-
import traceback
92-
traceback.print_exc()
93-
94-
self._start_timer(clean_closed_connections)
95-
96-
self._start_timer(clean_closed_connections)
97-
98-
def _start_timer(self, f):
99-
from threading import Timer
100-
101-
with self._lock:
102-
if not self._stopped:
103-
self._timer = Timer(30.0, f)
104-
self._timer.daemon = True
105-
self._timer.start()
106-
107-
def stop(self):
108-
with self._lock:
109-
self._stopped = True
110-
if self._timer:
111-
self._timer.cancel()
112-
self._timer = None
113-
114-
11557
class SparkContext(object):
11658

11759
"""
@@ -126,7 +68,6 @@ class SparkContext(object):
12668
_active_spark_context = None
12769
_lock = RLock()
12870
_python_includes = None # zip and egg files that need to be added to PYTHONPATH
129-
_py4j_cleaner = None
13071

13172
PACKAGE_EXTENSIONS = ('.zip', '.egg', '.jar')
13273

@@ -303,8 +244,6 @@ def _ensure_initialized(cls, instance=None, gateway=None):
303244
if not SparkContext._gateway:
304245
SparkContext._gateway = gateway or launch_gateway()
305246
SparkContext._jvm = SparkContext._gateway.jvm
306-
_py4j_cleaner = Py4jCallbackConnectionCleaner(SparkContext._gateway)
307-
_py4j_cleaner.start()
308247

309248
if instance:
310249
if (SparkContext._active_spark_context and

python/pyspark/streaming/context.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import os
2121
import sys
22+
from threading import RLock, Timer
2223

2324
from py4j.java_gateway import java_import, JavaObject
2425

@@ -32,6 +33,63 @@
3233
__all__ = ["StreamingContext"]
3334

3435

36+
class Py4jCallbackConnectionCleaner(object):
37+
38+
"""
39+
A cleaner to clean up callback connections that are not closed by Py4j. See SPARK-12617.
40+
It will scan all callback connections every 30 seconds and close the dead connections.
41+
"""
42+
43+
def __init__(self, gateway):
44+
self._gateway = gateway
45+
self._stopped = False
46+
self._timer = None
47+
self._lock = RLock()
48+
49+
def start(self):
50+
if self._stopped:
51+
return
52+
53+
def clean_closed_connections():
54+
from py4j.java_gateway import quiet_close, quiet_shutdown
55+
56+
callback_server = self._gateway._callback_server
57+
if callback_server:
58+
with callback_server.lock:
59+
try:
60+
closed_connections = []
61+
for connection in callback_server.connections:
62+
if not connection.isAlive():
63+
quiet_close(connection.input)
64+
quiet_shutdown(connection.socket)
65+
quiet_close(connection.socket)
66+
closed_connections.append(connection)
67+
68+
for closed_connection in closed_connections:
69+
callback_server.connections.remove(closed_connection)
70+
except Exception:
71+
import traceback
72+
traceback.print_exc()
73+
74+
self._start_timer(clean_closed_connections)
75+
76+
self._start_timer(clean_closed_connections)
77+
78+
def _start_timer(self, f):
79+
with self._lock:
80+
if not self._stopped:
81+
self._timer = Timer(30.0, f)
82+
self._timer.daemon = True
83+
self._timer.start()
84+
85+
def stop(self):
86+
with self._lock:
87+
self._stopped = True
88+
if self._timer:
89+
self._timer.cancel()
90+
self._timer = None
91+
92+
3593
class StreamingContext(object):
3694
"""
3795
Main entry point for Spark Streaming functionality. A StreamingContext
@@ -47,6 +105,9 @@ class StreamingContext(object):
47105
# Reference to a currently active StreamingContext
48106
_activeContext = None
49107

108+
# A cleaner to clean leak sockets of callback server every 30 seconds
109+
_py4j_cleaner = None
110+
50111
def __init__(self, sparkContext, batchDuration=None, jssc=None):
51112
"""
52113
Create a new StreamingContext.
@@ -95,6 +156,8 @@ def _ensure_initialized(cls):
95156
jgws = JavaObject("GATEWAY_SERVER", gw._gateway_client)
96157
# update the port of CallbackClient with real port
97158
gw.jvm.PythonDStream.updatePythonGatewayPort(jgws, gw._python_proxy_port)
159+
_py4j_cleaner = Py4jCallbackConnectionCleaner(gw)
160+
_py4j_cleaner.start()
98161

99162
# register serializer for TransformFunction
100163
# it happens before creating SparkContext when loading from checkpointing

0 commit comments

Comments
 (0)