4
4
import struct
5
5
from threading import local
6
6
7
- from kafka .common import BufferUnderflowError
8
7
from kafka .common import ConnectionError
9
8
10
9
log = logging .getLogger ("kafka" )
@@ -19,14 +18,14 @@ class KafkaConnection(local):
19
18
we can do something in here to facilitate multiplexed requests/responses
20
19
since the Kafka API includes a correlation id.
21
20
"""
22
- def __init__ (self , host , port , bufsize = 4096 ):
21
+ def __init__ (self , host , port , timeout = 10 ):
23
22
super (KafkaConnection , self ).__init__ ()
24
23
self .host = host
25
24
self .port = port
26
- self .bufsize = bufsize
27
25
self ._sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
28
26
self ._sock .connect ((host , port ))
29
- self ._sock .settimeout (10 )
27
+ self .timeout = timeout
28
+ self ._sock .settimeout (self .timeout )
30
29
self ._dirty = False
31
30
32
31
def __str__ (self ):
@@ -36,44 +35,31 @@ def __str__(self):
36
35
# Private API #
37
36
###################
38
37
39
- def _consume_response (self ):
40
- """
41
- Fully consume the response iterator
42
- """
43
- return "" .join (self ._consume_response_iter ())
44
-
45
- def _consume_response_iter (self ):
46
- """
47
- This method handles the response header and error messages. It
48
- then returns an iterator for the chunks of the response
49
- """
50
- log .debug ("Handling response from Kafka" )
51
-
52
- # Read the size off of the header
53
- resp = self ._sock .recv (4 )
54
- if resp == "" :
55
- self ._raise_connection_error ()
56
- (size ,) = struct .unpack ('>i' , resp )
57
-
58
- messagesize = size - 4
59
- log .debug ("About to read %d bytes from Kafka" , messagesize )
60
-
61
- # Read the remainder of the response
62
- total = 0
63
- while total < messagesize :
64
- resp = self ._sock .recv (self .bufsize )
65
- log .debug ("Read %d bytes from Kafka" , len (resp ))
66
- if resp == "" :
67
- raise BufferUnderflowError (
68
- "Not enough data to read this response" )
69
-
70
- total += len (resp )
71
- yield resp
72
-
73
38
def _raise_connection_error (self ):
74
39
self ._dirty = True
75
40
raise ConnectionError ("Kafka @ {}:{} went away" .format (self .host , self .port ))
76
41
42
+ def _read_bytes (self , num_bytes ):
43
+ bytes_left = num_bytes
44
+ resp = ''
45
+ log .debug ("About to read %d bytes from Kafka" , num_bytes )
46
+ if self ._dirty :
47
+ self .reinit ()
48
+ while bytes_left :
49
+ try :
50
+ data = self ._sock .recv (bytes_left )
51
+ except socket .error :
52
+ log .exception ('Unable to receive data from Kafka' )
53
+ self ._raise_connection_error ()
54
+ if data == '' :
55
+ log .error ("Not enough data to read this response" )
56
+ self ._raise_connection_error ()
57
+ bytes_left -= len (data )
58
+ log .debug ("Read %d/%d bytes from Kafka" , num_bytes - bytes_left , num_bytes )
59
+ resp += data
60
+
61
+ return resp
62
+
77
63
##################
78
64
# Public API #
79
65
##################
@@ -89,7 +75,7 @@ def send(self, request_id, payload):
89
75
sent = self ._sock .sendall (payload )
90
76
if sent is not None :
91
77
self ._raise_connection_error ()
92
- except socket .error :
78
+ except socket .error , e :
93
79
log .exception ('Unable to send payload to Kafka' )
94
80
self ._raise_connection_error ()
95
81
@@ -98,8 +84,14 @@ def recv(self, request_id):
98
84
Get a response from Kafka
99
85
"""
100
86
log .debug ("Reading response %d from Kafka" % request_id )
101
- self .data = self ._consume_response ()
102
- return self .data
87
+ # Read the size off of the header
88
+ resp = self ._read_bytes (4 )
89
+
90
+ (size ,) = struct .unpack ('>i' , resp )
91
+
92
+ # Read the remainder of the response
93
+ resp = self ._read_bytes (size )
94
+ return str (resp )
103
95
104
96
def copy (self ):
105
97
"""
@@ -124,5 +116,5 @@ def reinit(self):
124
116
self .close ()
125
117
self ._sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
126
118
self ._sock .connect ((self .host , self .port ))
127
- self ._sock .settimeout (10 )
119
+ self ._sock .settimeout (self . timeout )
128
120
self ._dirty = False
0 commit comments