how to make autobahn / twisted websocket server restart / stay up after exception - python

I have a websocket server using autobahn where it runs some code onMessage.
during this code an exception happens and I perform a try/except clause so I can log the error, it logs correctly. However the connection to the client(javascript) disconnects.
The problem is that if I load a new page it does not reconnect to the websocket server. I attempted to put the code block to start the server in a while loop but the client does not connect succesfully.
if __name__ == '__main__':
import sys
from twisted.python import log
from twisted.internet import reactor, task, threads
logging.basicConfig(filename='/var/log/myerror.log', level=logging.ERROR)
log.startLogging(sys.stdout)
factory = WebSocketServerFactory(u"ws://127.0.0.1:9000", debug=False)
factory.protocol = MyServerProtocol
factory.setProtocolOptions(maxConnections=50)
reactor.listenTCP(9000, factory)
reactor.run()
Does anyone know how to make it so even if the code in 'onMessage' has an exception, the websocket server will continue to accept connections and give other clients the opportunity to run?

Found the problem. I had placed 'reactor.callFromThread(reactor.stop) ' elsewhere in the code and it was killing the reactor.

Related

Flask SocketIO - connect client to server immediately after server start

I've created a single socket endpoint on the server side that looks like this:
Server.py
from client import sockio_client
from flask_socketio import SocketIO
from flask import Flask
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on('status_update')
def status_update(data):
print('got something: ',data)
#app.before_first_request
def start_ws_client():
# now that server is started, connect client
sockio_client.connect('http://localhost:5000')
if __name__ == "__main__":
socketio.run(app,debug=True)
And the corresponding client:
Client.py
import socketio
from threading import Thread
sockio_client = socketio.Client()
# wait to connect until server actually started
# bunch of code
def updater():
while True:
sockio_client.emit('status_update', 42)
time.sleep(10)
t = Thread(target=updater)
t.start()
I've got a single background thread running outside of the server and I would like to update clients with the data it periodically emits. I'm sure there is more than one way to do this, but the two options I came up with were to either (i) pass a reference to the socketio object in server.py above to the update function in client by encapsulating the update function in an object or closure which has a reference to the socketio object, or (ii) just use a websocket client from the background job to communicate to the server. Option one just felt funny so I went with (ii), which feels... okish
Now obviously the server has to be running before I can connect the client, so I thought I could use the before_first_request decorator to make sure I only attempt to connect the client after the server has started. However every time I try, I get:
socketio.exceptions.ConnectionError: Connection refused by the server
At this point the server is definitely running, but no connections will be accepted. If I were to comment out the sockio_client.connect in server.py, and connect from an entirely separate script, everything works as expected. What am I doing wrong? Also, if there are much better ways to do this, please tear it apart.

Twisted client failed to connect working differently on Windows to Linux/MacOS

I am trying to detect a failed connection when using the Twisted endpoint connect() function. What is odd is that the following works under Windows and gives the expected result, but on a Linux/Mac OS system I am never seeing the print statement from errBack. Is my code incorrect or does Windows Twisted work differently from the rest?
class Gateway():
def __init__(self):
from twisted.internet.endpoints import TCP4ClientEndpoint
endpoint = TCP4ClientEndpoint(reactor, 'localhost', 8000)
authInterfaceFactory = AuthInterfaceFactory(self.__authMsgProcessor)
d = endpoint.connect(authInterfaceFactory)
d.addErrback(self.ConnFailed)
print("WAITING...")
def ConnFailed(self, msg):
print("[DEBUG] Errback : {0}".format(msg))
Windows Result
WAITING... [DEBUG] Errback : [Failure instance: Traceback (failure
with no frames): : Connection was
refused by other side: 10061: No connection could be made because the
target machine actively refused it..]
I created a client that uses endpoint connect and it immediately returned, although when used it in the same setup as my code it doesn't:
self.__networkThread = threading.Thread(target=reactor.run,
kwargs={"installSignalHandlers": False})
self.__networkThread.start()
from twisted.internet.endpoints import TCP4ClientEndpoint
endpoint = TCP4ClientEndpoint(reactor, 'localhost', 8000)
d = endpoint.connect(authInterfaceFactory)
d.addErrback(self.ConnFailed)
d.addCallback(self.ConnOK)
Is the logic incorrect when running a reactor in a thread (I have to as I want it started at the beginning)?
You can't run the reactor in one thread and use Twisted APIs in another. Apart from a couple APIs dedicated specifically to interacting with threads, you must use all Twisted APIs from a single thread.
"I want it started at the beginning" doesn't sound like a reason to use threads. Many many Twisted-using programs start the reactor "at the beginning" without threads.
(Also please take this as an excellent example of the need for complete examples.)

Detect when Websocket is disconnected, with Python Bottle / gevent-websocket

I'm using the gevent-websocket module with Bottle Python framework.
When a client closes the browser, this code
$(window).on('beforeunload', function() { ws.close(); });
helps to close the websocket connection properly.
But if the client's network connection is interrupted, no "close" information can be sent to the server.
Then, often, even 1 minute later, the server still believes the client is connected, and the websocket is still open on the server.
Question: How to detect properly that a websocket is closed because the client is disconnected from network?
Is there a websocket KeepAlive feature available in Python/Bottle/gevent-websocket?
One answer from Web Socket: cannot detect client connection on internet disconnect suggests to use a heartbeat/ping packet every x seconds to tell the server "I'm still alive". The other answer suggests using a setKeepAlive(true). feature. Would this feature be available in gevent-websocket?
Example server code, taken from here:
from bottle import get, template, run
from bottle.ext.websocket import GeventWebSocketServer
from bottle.ext.websocket import websocket
users = set()
#get('/')
def index():
return template('index')
#get('/websocket', apply=[websocket])
def chat(ws):
users.add(ws)
while True:
msg = ws.receive()
if msg is not None:
for u in users:
u.send(msg)
else:
break
users.remove(ws)
run(host='127.0.0.1', port=8080, server=GeventWebSocketServer)
First you need to add a timeout to the receive() method.
with gevent.Timeout(1.0, False):
msg = ws.receive()
Then the loop will not block, if you send even an empty packet and the client doesn't respond, WebsocketError will be thrown and you can close the socket.

How detect client "socket.close()" in tornado socket server

I am implementing a tornado socket server based on this code:
https://gist.github.com/robcowie/974695
Client is Python simple socket client. When I call socket.close() in client, nothing happens in server. I put full print traces in the server and closing is not detected nowhere.
I know I can detect the closure for example sending a string "CNNDEND" which means closing. But I wonder if there is any way to detect on server socket.close() from client.
in Connection __init__:
self.stream.set_close_callback(self.__onClose)
in Connection class:
def __onClose(self):
print 'close detected'

How to stop a Flask server running gevent-socketio

I have a flask application running with gevent-socketio that I create this way:
server = SocketIOServer(('localhost', 2345), app, resource='socket.io')
gevent.spawn(send_queued_messages_loop, server)
server.serve_forever()
I launch send_queued_messages_loop in a gevent thread that keeps on polling on a gevent.Queue where my program stores data to send it to the socket.io connected clients
I tried different approaches to stop the server (such as using sys.exit) either from the socket.io handler (when the client sends a socket.io message) or from a normal route (when the client makes a request to /shutdown) but in any case, sys.exit seems to fail because of the presence of greenlets.
I tried to call gevent.shutdown() first, but this does not seem to change anything
What would be the proper way to shutdown the server?
Instead of using serve_forever() create a gevent.event.Event and wait for it. To actually initiate shutdown, trigger the event using its set() method:
from gevent.event import Event
stopper = Event()
server = SocketIOServer(('localhost', 2345), app, resource='socket.io')
server.start()
gevent.spawn(send_queued_messages_loop)
try:
stopper.wait()
except KeyboardInterrupt:
print
No matter from where you now want to terminate your process - all you need to do is calling stopper.set().
The try..except is not really necessary but I prefer not getting a stacktrace on a clean CTRL-C exit.

Categories