After a server upgrade, I'm having an issue with a python script eating up all the server connections because it appears that after a timeout it doesn't actually end the loop. The code looks like:
if os.name == 'posix':
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(__TIMEOUT__)
try:
self.inputline = self.rfile.readline()
except IOError:
continue
if os.name == 'posix':
signal.alarm(0)
The signal occurs and all that does is set a terminated variable to 1 and print a log about the time out. The while looks like while not self.terminated:. My guess is that because it has except IOError: the except doesn't occur and it's still sitting on the readline(). So the question is, what is the proper way to ensure the SIGALRM will cause the continue which will end the loop and exit the script?
TIA!!
In handle_timeout() you can raise an exception to get your try to wake up. Then catch that exception in your try/except:
def handle_timeout(signum, frame):
raise KeyboardInterrupt('received signal to exit')
while not terminated:
try:
self.inputline = self.rfile.readline()
except IOError, KeyboardInterrupt:
terminated = True
continue
Related
The bounty expires in 5 days. Answers to this question are eligible for a +50 reputation bounty.
chakmeshma wants to draw more attention to this question.
I'm writing a simple TCP relay server, which is gonna be deployed both on a Windows and a Linux machine (same code base).
Naturally there're gonna be two sockets to work with.
I would like to know which exceptions exactly do get raised for the following cases:
recv() returns when no data is available to read.
sendall() cannot complete (dispose of the whole to-send data)
Do I have to check for both errnos (socket.EWOULDBLOCK and socket.EAGAIN) when expecting to return from a non-blocking sockets recv()?
Which errno (.args[0]) do I get when sendall() fails?
Here's my code so far:
try:
socket1.setblocking(False)
socket2.setblocking(False)
while True:
try:
sock1_data = socket1.recv(1024)
if sock1_data:
socket2.sendall(sock1_data)
except socket.error as e:
if e.args[0] != socket.EAGAIN and e.args[0] != socket.EWOULDBLOCK:
raise e
try:
sock2_data = socket2.recv(1024)
if sock2_data:
socket1.sendall(sock2_data)
except socket.error as e:
if e.args[0] != socket.EAGAIN and e.args[0] != socket.EWOULDBLOCK:
raise e
except:
pass
finally:
if socket2:
socket2.close()
if socket1:
socket1.close()
My main concern is:
What socket.error.errno do I get when sendall() fails?
Lest the socket.error.errno I get from a failing sendall() is EAGAIN or EWOULDBLOCK, in which case it'd be troubling!!
Also, do I have to check for both EAGAIN and EWOULDBLOCK when handling a non-blocking recv()?
If disconnect is called, I want to restart the main method from the connection.py file. Main method does not restart with existing code when disconnect occurs.
connection.py file*
def disconnect(flags):
#do something
raise RuntimeError('You have been disconnected')
main.py file*
import connection
def main():
while True:
try:
#do something to invoke disconnect
except RuntimeError('You have been disconnected'):
main()
main()
Your try-except block is wrong. I ran your code in python3, and it raised a very clear error, "builtins.TypeError: catching classes that do not inherit from BaseException is not allowed" Because of that unhandled exception, you exit main.
Try these:
try:
raise RuntimeError('You have been disconnected')
except RuntimeError:
print ('caught')
try:
raise RuntimeError('You have been disconnected')
except RuntimeError as e:
print (str(e))
Because you already have a while loop in main, there's no need to recursively call main again. Just let the while loop do its job:
def main():
while True:
connect()
try:
raise RuntimeError('You have been disconnected')
except RuntimeError as e:
print (str(e))
If the error is caught, then you will still be inside the while loop.
I am trying to handle a hard to duplicate error case using TCPServer. We have seen a few occurrences that when a socket timeout happens in the handler, the code never recovers and keeps returning the socket.timeout exception.
This looks to be from the following snippet in the Socket.py library code:
def readinto(self, b):
"""Read up to len(b) bytes into the writable buffer *b* and return
the number of bytes read. If the socket is non-blocking and no bytes
are available, None is returned.
If *b* is non-empty, a 0 return value indicates that the connection
was shutdown at the other end.
"""
self._checkClosed()
self._checkReadable()
if self._timeout_occurred:
raise OSError("cannot read from timed out object")
while True:
try:
return self._sock.recv_into(b)
except timeout:
self._timeout_occurred = True
raise
except InterruptedError:
continue
except error as e:
if e.args[0] in _blocking_errnos:
return None
raise
once a timeout has occurred _timeout_occurred is set to True, and the next pass into this function, the socket has the flag set, and will immediately exit with the cannot read from timed out object error.
Now the code uses TCP Server (only relevant code included) Basically it is reading stuff from the socket, and queing it to be handled separately.
def get_event(file_):
pre_package_len = 8
msg = file_.read(pre_package_len)
if len(msg) == pre_package_len:
pkg = PRE_PACKAGE_FRAME.unpack(msg)
msg = file_.read(pkg['len'])
logger.debug('recv: type: %s len: %s bytes read: %s',
pkg['type'], pkg['len'], len(msg))
if len(msg) >= pkg['len']:
if pkg['type'] == cdefs.kNotification:
e = EVENT_FRAME.unpack(msg)
return decode_event(e)
logger.warn('received unsupported package type: %s', pkg['type'])
else:
logger.error('failed to recv')
class _EventHandler(StreamRequestHandler):
def handle(self):
logger.debug("Got event from %s", self.client_address)
try:
e = get_event(self.rfile)
if e:
self.q.put(e)
except socket.timeout:
logger.error('timed out reading event')
def process_event(q, handler, shutdown_sentinel):
for e in iter(q.get, shutdown_sentinel):
try:
handler(e)
except Exception:
logger.exception('Unhandled exception handling event: %s', e)
logger.info('exiting')
def eventhandler_maker(q, timeout):
return type('NewEventHandler',
(_EventHandler, object),
dict(q=q, timeout=timeout))
def process_events(handler, address, timeout=20):
sentinel = object()
q = Queue()
eventhandler = eventhandler_maker(q, timeout)
server = TCPServer(address, eventhandler)
start_thread(server.serve_forever)
start_thread(process_event, (q, handler, sentinel))
def shutdown():
logger.info('shutting down')
q.put(sentinel)
server.shutdown()
def add_event(e):
q.put(e)
return shutdown, add_event
The symptoms are that once the timeout happens, the log keeps showing 'timed out reading event' and the code never does anything anymore. I added code to dump out the server.socket.gettimeout() and socket.getdefaulttimeout() and both return None. This application is running on an embedded Linux 3.10 kernel with python 3.4.0.
I have 2 questions here:
What is a good recovery strategy here? Shutdown() / Close() the server socket and then restart it? Or are there better strategies?
Is there a good third party tool to provoke a timeout so a recovery strategy can be proven to be correct?
I'm attempting to code a try-except loop that refreshes a webpage if it fails to load. Here's what I've done so far:
driver.get("url")
while True:
try:
<operation>
except:
driver.refresh()
I want to set this loop up so that if 5 seconds elapse and the operation is not executed (presumably because the page did not load), it attempts to refresh the page. Is there an exception we can incorporate in except that catches the time delay?
I would recommend reading this post Timeout function if it takes too long to finish.
The gist of it is that you can use signals to interrupt the code and raise an error, which you then catch.
In you example:
def _handle_timeout(signum,frame):
raise TimeoutError("Execution timed out")
driver.get("url")
signal.signal(signal.SIGALRM, _handle_timeout)
while True:
try:
signal.alarm(<timeout value>)
<operation>
signal.alarm(0)
except:
driver.refresh()
You can test this with the following snippet:
import time
import signal
def _handle_timeout(signum,frame):
raise TimeoutError("Execution timed out")
def test(timeout,execution_time):
signal.signal(signal.SIGALRM, _handle_timeout)
try:
signal.alarm(timeout)
time.sleep(execution_time)
signal.alarm(0)
except:
raise
else:
print "Executed successfully"
This will raise an error when execution_time > timeout.
As noted here in Python signal don't work even on Cygwin? the above code will not work on windows machines.
I have a try/except block that sends a message and waits for confirmation from client. If the client terminates, pickle raises an EOFError, but the code below does not catch the error and execute the graceful shut down. It instead prints stack trace. I assume it has to do with the line "except socket.error, EOFError:" - am I using the wrong syntax to handle both socket.error and EOFError there?
try:
msgs = [1]
self.sock.send(pickle.dumps(msgs))
rdy = pickle.loads(self.sock.recv(2097152))
except socket.error, EOFError:
print 'log socketmanager closing'
self.terminate()
break
In Python 2.x, the form except a, b catches an exception of type a and assign it to a variable called b. In your case this would result in EOFError being ignored. Try this instead:
...
except (socket.error, EOFError):
...
Edit: to elaborate, the new syntax in Python 3.0, and available, though not required, in 2.6+, for capturing the value of an exception is except a as b.
break is causing the error, it can only be used inside a for loop or a try/finally block, not try/except, see docs and more.