I'm currently running flask-socketio inside to a thread. On a specific socketio event, I want to change the state of a global object in main thread i.e, perform a function which might change its instance variable's values
In my actual program, 'self.params' is a list of chromedrivers. When a signal is emited a driver is removed or added. Does that make a difference? Chromedriver is a un-picklable object.
Here's a flask socketio code which a simplified sample:
from gevent import get_hub
get_hub().NOT_ERROR += (KeyboardInterrupt,)
from flask import Flask
from flask_socketio import SocketIO, emit
import threading
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecret'
socketio = SocketIO(app, cors_allowed_origins="*")
class SomeObj():
def __init__(self, param):
self.param = param
def query(self):
self.param += 1
return
global_obj = SomeObj(0)
#socketio.on('msg')
def handle_msg():
global_obj.query()
def start():
def run():
socketio.run(app, port=5005)
SocketIOThread = threading.Thread(target=run)
SocketIOThread.daemon = True
SocketIOThread.start()
if __name__ == '__main__':
start()
while True:
a = input()
if a == '`':
break
else:
print(global_obj.param)
How can i achive this? I get only 0 every time.
Related
Every time when I refresh the page from client side a new connection is made with the flask server and it runs the function 'backgroundFunction()' without exiting the recent opened function and the number increases as I refresh the page again and again.
from flask import Flask
from flask_socketio import SocketIO, send, emit
import socket
from time import sleep
import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['DEBUG'] = True
socketio = SocketIO(app , cors_allowed_origins="*" , async_mode = None , logger = False , engineio_logger = False)
def backgroundFunction():
while True:
data = "I am Data"
socketio.emit('data', data, broadcast=True)
socketio.sleep(2)
#socketio.on('connect')
def socketcon():
print('Client connected')
socketio.start_background_task(backgroundFunction)
if __name__ == ("__main__"):
socketio.run(app, port=5009)
Look at the example code in the Flask-SocketIO repository to learn one possible way to implement a background job that starts the first time an event is triggered.
Code is here. Here is the relevant excerpt:
thread = None
thread_lock = Lock()
def background_thread():
"""Example of how to send server generated events to clients."""
count = 0
while True:
socketio.sleep(10)
count += 1
socketio.emit('my_response',
{'data': 'Server generated event', 'count': count})
#socketio.event
def connect():
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(background_thread)
My webapp runs from inside a function because im multithreading with other functions (only 1 instance of flask), and my questions are:
A. What is the best way to pass a Queue into the app?
B. When passed, how can the Queue be used inside a specific route?
Here is the relevant part of the code ive written so far, which gives and error "global name 'queue' is not defined" when a request is made to "/parser".
app = Flask(__name__)
q = Queue()
app.config['queue'] = q;
#app.route('/parser')
def Parser():
arg = request.args.get('arg') #if key doesn't exist, returns None
queue.put(arg)
def Run():
app.run(debug=False, host='0.0.0.0')
if __name__ == '__main__':
q = Queue()
app.config['queue'] = q;
thread = Thread(target = Run)
thread.start()
Thanks in advance :)
Edit: Added a code sample that might be of help
from flask import Flask
from threading import Thread
from queue import Queue
app = Flask(__name__)
q = Queue()
app.config['queue'] = q;
app.config['test'] = 'testing';
#app.route('/insert/<var>')
def Insert(var):
q = app.config['queue']
q.put(var)
return "Ok"
#app.route('/pop')
def Get():
q = app.config['queue']
return q.get()
def Run():
app.run(debug=False, host='0.0.0.0')
if __name__ == '__main__':
thread = Thread(target = Run)
thread.start()
I am pretty sure that flask does not support running the same app instance in multiple threads.
I have a feeling that this is an instance of XY problem,
If you are deploying on production, this page lists some ways to do so that can handle multiple concurrent connections.
I have a Flask script which creates a website and prints some data dynamically. - The data which it prints should come from another python script.
The current problem that I'm facing is that if I put the line that executes the python script before the line that executes the Flask app, it will run the Python script without running Flask; and vice versa.
Python script:
import websocket
from bitmex_websocket import Instrument
from bitmex_websocket.constants import InstrumentChannels
from bitmex_websocket.constants import Channels
import json
websocket.enableTrace(True)
sells = 0
buys = 0
channels = [
InstrumentChannels.trade,
]
XBTUSD = Instrument(symbol='XBTUSD',
channels=channels)
XBTUSD.on('action', lambda msg: test(msg))
def test(msg):
parsed = json.loads(json.dumps(msg))
print(parsed)
XBTUSD.run_forever()
Flask script (NB: price should be the variable 'parsed' from the other script):
# Start with a basic flask app webpage.
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, url_for, copy_current_request_context
from random import random
from time import sleep
from threading import Thread, Event
import requests, json
import time
__author__ = 'slynn'
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
#turn the flask app into a socketio app
socketio = SocketIO(app)
#random number Generator Thread
thread = Thread()
thread_stop_event = Event()
class RandomThread(Thread):
def __init__(self):
self.delay = 1
super(RandomThread, self).__init__()
def randomNumberGenerator(self):
while not thread_stop_event.isSet():
socketio.emit('newnumber', {'number': parsed}, namespace='/test')
sleep(self.delay)
def run(self):
self.randomNumberGenerator()
#app.route('/')
def index():
#only by sending this page first will the client be connected to the socketio instance
return render_template('index.html')
#socketio.on('connect', namespace='/test')
def test_connect():
# need visibility of the global thread object
global thread
print('Client connected')
#Start the random number generator thread only if the thread has not been started before.
if not thread.isAlive():
print("Starting Thread")
thread = RandomThread()
thread.start()
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
Using import:
Wrap what the python script (e.g. website_generator.py) is generating into a function.
Place it in the same directory as your app.py or flask.py.
Use from website_generator import function_name in flask.py
Run it using function_name()
You can use other functions such as subprocess.call et cetera; although they might not give you the response.
Example using import:
from flask import Flask
import your_module # this will be your file name; minus the `.py`
app = Flask(__name__)
#app.route('/')
def dynamic_page():
return your_module.your_function_in_the_module()
if __name__ == '__main__':
app.run(host='0.0.0.0', port='8000', debug=True)
try this:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def run_script():
file = open(r'/path/to/your/file.py', 'r').read()
return exec(file)
if __name__ == "__main__":
app.run(debug=True)
I have code that can send messages up to a connected user with socketio.emit(), but when doing the same thing from a gevent thread, the data never makes it to the client.
Sample code:
from flask import Flask, request, render_template
from flask_socketio import SocketIO, join_room, leave_room, emit
import gevent
from gevent import monkey
monkey.patch_all()
app = Flask(__name__)
app.config['SECRET_KEY'] = '<redacted>'
app.debug = False
socket = SocketIO(app, async_mode="gevent")
def sendStamina(sessionId, stamina):
# have to use socket.emit here, simply because this function is called from an BG thread.
with app.test_request_context('/'):
socket.emit('stamina', {'sessiondId': sessionId, 'stamina': stamina}, room=sessionId)
print("sent satmina update")
def stamina_update():
print("stamina update called")
next_call = time.time()
while 1:
print("stamina update called inside")
next_call = next_call + 1
gevent.sleep(next_call - time.time())
sendStamina(<data>, <data>)
t1 = gevent.spawn(game.stamina_update)
t2 = gevent.spawn(start_server)
gevent.joinall([t1, t2])
I've seen a few threads about this on SO and socketio's forums, and it's gotten me closer, but I'm still missing something...
I have a pyhton-socketio server that servers on port 8000 and handles connections perfectly. I want to emit the following emit message every 2 seconds. When emitting the client doesn't receive a message. If I emit from where I point out in the comment it works perfect.
How can I edit this to be able to emit from inside the while loop successfully?
The python server code:
import socketio
import eventlet
import threading
import time
from flask import Flask, render_template
sio = socketio.Server()
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
# as a decorator:
#sio.on('connect')
def connect_handler(sid, environ):
print('IP->' + environ['REMOTE_ADDR'])
# If I emit here it works e.g. sio.emit('status-update', {'core0_in': 8, 'core1_in': 12,'cpu_usage_in': 5, 'users': 7})
#sio.on('disconnect')
def disconnect(sid):
print('disconnect ', sid)
class Server(threading.Thread):
def __init__(self, thread_id):
threading.Thread.__init__(self)
self.threadID = thread_id
def run(self):
print("Starting " + self.name)
serve()
def serve():
if __name__ == '__main__':
global app
# wrap Flask application with socketio's middleware
app = socketio.Middleware(sio, app)
# deploy as an eventlet WSGI server
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
server_thread = Server("Server-thread")
server_thread.start()
while True:
print("Emitting...")
sio.emit('status-update', {'core0_in': 8, 'core1_in': 12,'cpu_usage_in': 5, 'users': 7}) # when emitting here the client doesn't receive anything
time.sleep(2)