def _recv_msg(self, mid_stream=False): """ :param mid_stream: are we receiving in a streaming operation? :type mid_stream: boolean """ try: msgbuf = self._recv_pkt() except BadResource as e: e.mid_stream = mid_stream raise except socket.timeout as e: # A timeout can leave the socket in an inconsistent state because # it might still receive the data later and mix up with a # subsequent request. # https://github.com/basho/riak-python-client/issues/425 raise BadResource(e, mid_stream) mv = memoryview(msgbuf) mcb = mv[0:1] if self.bytes_required: mcb = mcb.tobytes() try: msg_code, = struct.unpack("B", mcb) except struct.error: # NB: Python 2.7.3 requires this # http://bugs.python.org/issue10212 msg_code, = struct.unpack("B", mv[0:1].tobytes()) self.bytes_required = True data = mv[1:].tobytes() return (msg_code, data)
def test_bad_resource_inner_exception(self): ex_msg = 'exception-message!' ex = RiakError(ex_msg) with self.assertRaises(BadResource) as cm: raise BadResource(ex) br_ex = cm.exception self.assertEqual(br_ex.args[0], ex)
def _with_retries(self, pool, fn): """ Performs the passed function with retries against the given pool. :param pool: the connection pool to use :type pool: Pool :param fn: the function to pass a transport :type fn: function """ skip_nodes = [] def _skip_bad_nodes(transport): return transport._node not in skip_nodes retry_count = self.RETRY_COUNT for retry in range(retry_count): try: with pool.take(_filter=_skip_bad_nodes) as transport: try: return fn(transport) except (IOError, httplib.HTTPException) as e: if _is_retryable(e): transport._node.error_rate.incr(1) skip_nodes.append(transport._node) raise BadResource(e) else: raise except BadResource as e: if retry < (retry_count - 1): continue else: # Re-raise the inner exception raise e.args[0]
def _with_retries(self, pool, fn): """ Performs the passed function with retries against the given pool. :param pool: the connection pool to use :type pool: Pool :param fn: the function to pass a transport :type fn: function """ skip_nodes = [] def _skip_bad_nodes(transport): return transport._node not in skip_nodes retry_count = self.retries - 1 first_try = True current_try = 0 while True: try: with pool.transaction( _filter=_skip_bad_nodes, yield_resource=True) as resource: transport = resource.object try: return fn(transport) except (IOError, HTTPException, ConnectionClosed) as e: resource.errored = True if _is_retryable(e): transport._node.error_rate.incr(1) skip_nodes.append(transport._node) if first_try: continue else: raise BadResource(e) else: raise except BadResource as e: if current_try < retry_count: resource.errored = True current_try += 1 continue else: # Re-raise the inner exception raise e.args[0] finally: first_try = False
def _recv(self, msglen): # TODO FUTURE re-use buffer # http://stackoverflow.com/a/15964489 msgbuf = bytearray(msglen) view = memoryview(msgbuf) nread = 0 toread = msglen while toread: nbytes = self._socket.recv_into(view, toread) # https://docs.python.org/2/howto/sockets.html#using-a-socket # https://github.com/basho/riak-python-client/issues/399 if nbytes == 0: ex = RiakError('recv_into returned zero bytes unexpectedly') raise BadResource(ex) view = view[nbytes:] # slicing views is cheap toread -= nbytes nread += nbytes if nread != msglen: raise RiakError("Socket returned short packet %d - expected %d" % (nread, msglen)) return msgbuf
def _request(self, msg, codec=None): if isinstance(msg, Msg): msg_code = msg.msg_code data = msg.data expect = msg.resp_code else: raise ValueError('expected a Msg argument') if not isinstance(codec, Codec): raise ValueError('expected a Codec argument') resp_code, data = self._send_recv(msg_code, data) # NB: decodes errors with msg code 0 codec.maybe_riak_error(resp_code, data) codec.maybe_incorrect_code(resp_code, expect) if resp_code == MSG_CODE_TS_TTB_MSG or \ resp_code in riak.pb.messages.MESSAGE_CLASSES: msg = codec.parse_msg(resp_code, data) else: # NB: raise a BadResource to ensure this connection is # closed and not re-used raise BadResource('unknown msg code {}'.format(resp_code)) return resp_code, msg
def test_can_raise_bad_resource(self): ex_msg = 'exception-message!' with self.assertRaises(BadResource) as cm: raise BadResource(ex_msg) ex = cm.exception self.assertEqual(ex.args[0], ex_msg)