Calling Celery task from SocketIO connect event - python

I would like to call my celery task when a websocket client connects to the socket server. When I try calling it from the connect event it causes the application to time out and the client does not receive the emit.
Below is an example of the code for the application:
from flask import Flask
from flask_socketio import SocketIO
import eventlet
from celery import Celery
import time
eventlet.monkey_patch(socket=True)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
socketio = SocketIO(app, async_mode='eventlet', logger=True, engineio_logger=True, message_queue='redis://127.0.0.1:6379' )
celery = Celery(app.name, broker='redis://127.0.0.1:6379')
celery.conf.update(app.config)
#app.route('/')
def home():
return 'Hello World!'
#socketio.on('connect')
def connect():
print('Client connected, calling celery task...')
celeryTask(1,2)
#celery.task()
def celeryTask(x,y):
print('Celery task called!')
local_socketio = SocketIO(app, logger=True, engineio_logger=True, message_queue='redis://127.0.0.1:6379')
while True:
local_socketio.emit('add', {'data': x+y})
time.sleep(60)
if __name__ == '__main__':
socketio.run(app, debug=True)
Any help would be greatly appreciated!

The socketio instance that you are using in your Celery task should not be initialized with the app instance from Flask. This isn't a web server, is just an auxiliary emitter.
#celery.task()
def celeryTask(x,y):
print('Celery task called!')
local_socketio = SocketIO(logger=True, engineio_logger=True, message_queue='redis://127.0.0.1:6379')
while True:
local_socketio.emit('add', {'data': x+y})
time.sleep(60)
If that does not work, you will need to add logs to your question, as that provide more clues.

Maybe try to put #celery.task() before #socketio.on('connect'). That might help.

Related

Flask socketIO connection established but not routed

For my project I have to connect one socketIO backend to another. For this I am using Flask-socketio and socketio-client. The code for both is the following:
CLIENT:
from socketIO_client import SocketIO, LoggingNamespace
ip = '192.168.1.41'
port = 8090
def handle_aaa_response():
print('response')
socketIO = SocketIO(ip, port)
socketIO.on('pingSuccess', on_aaa_response)
socketIO.wait(seconds=1)
SERVER:
from flask import Flask, render_template, jsonify, Response
from flask_socketio import SocketIO, emit
TRACE_LIBRARIES = False
HOST = '0.0.0.0'
WEB_PORT = 8090
USE_PIN = False
def handle_connect():
print('hello world')
emit('pingSuccess')
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
socketio = SocketIO(app, cors_allowed_origins="*")
socketio.on('connect', handle_connect)
try:
socketio.run(app,
host=HOST,
port=WEB_PORT,
log_output=True)
except KeyboardInterrupt:
print('*** User raised KeyboardInterrupt')
exit()
When i run the client and server, the server only logs the following:
(4743) accepted ('192.168.1.33', 53500)
192.168.1.33 - - [21/Oct/2020 15:48:31] "GET /socket.io/?EIO=3&transport=polling&t=1603291711742-0 HTTP/1.1" 200 371 0.005033
(4743) accepted ('192.168.1.33', 53502)
This means the server is accepting the connection from the client, but not routing to the correct route on the server.
I want to know how I can change this so it gets to the correct route and prints "hello world:
Contrary to socketio.on() from the regular socketIO_client package you use in your client script, flask_socketio uses .on() as a decorator.
So to add a callback to an event in flask_socketio, you would need to change the following:
...
socketio = SocketIO(app, cors_allowed_origins="*")
#socketio.on('connect')
def handle_connect():
print('hello world')
emit('pingSuccess')
...
Server Side
#socketio.on('connect')
def test_connect():
print('hello world')
emit('pingSuccess')

Python sockets with flask and vue for continious serial data stream

So I have an flask application which is extended by the flask_socketio package.
I currently have a vue front end, that connects to an socket.
Now the output of the socket connection in the following:
I also see an connection in the terminal of the flask application:
127.0.0.1 - - [23/Aug/2019 21:07:11] "GET /socket.io/?EIO=3&transport=polling&t=Mo_u1wR HTTP/1.1" 200
However, I have on my code that when the socket connects, there should start an thread with while true, to continious receive the data.
This is the code I have:
from flask import Flask, jsonify
from flask_socketio import SocketIO, send, emit
import threading
from threading import Lock
import time
import controllers.gpsController
# configuration
DEBUG = True
# instantiate the app
app = Flask(__name__)
app.config.from_object(__name__)
thread = None
thread_lock = Lock()
async_mode = None
# app.config['SECRET_KEY'] = 'secret!'
# enable CORS
socketio = SocketIO(app, cors_allowed_origins='*', async_mode=async_mode)
def activate_gps():
ser = controllers.gpsController.open_serial_connection()
while True:
data = controllers.gpsController.readGPS(ser)
if data != None:
socketio.emit('fetch_gps_data', data, broadcast=True)
socketio.sleep(0.1)
# Use sockets here
#socketio.on('connect')
def start_get_data_thread():
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(target=activate_gps)
if __name__ == '__main__':
socketio.run(app, host='127.0.0.1', port=12345)
Anyone an idea what I'm doing wrong here? If I have te code of activate_gps() in another file and call that, I get the wanted output.

How can I run a python script from within Flask

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)

Python-SocketIO server won't emit from the main section of the program

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)

gevent-socketio send message from thread

I would like to use gevent-socketio to send messages from a worker thread and update all connected clients on the status of the job.
I tried this:
from flask import Flask, render_template
from flask.ext.socketio import SocketIO, send, emit
import threading
import time
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#socketio.on('message')
def handle_message(message):
send(message, broadcast=True)
#app.route('/')
def index():
return render_template('index.html')
def ping_thread():
while True:
time.sleep(1)
print 'Pinging'
send('ping')
if __name__ == '__main__':
t = threading.Thread(target=ping_thread)
t.daemon = True
t.start()
socketio.run(app)
And it gives me this error:
RuntimeError: working outside of request context
How do I send messages from a function that doesn't have the #socketio.on() decorator? Can I use gevent directly to send messages to socketio?
From this section of the documentation:
Sometimes the server needs to be the originator of a message. This can be useful to send a notification to clients of an event that originated in the server. The socketio.send() and socketio.emit() methods can be used to broadcast to all connected clients:
def some_function():
socketio.emit('some event', {'data': 42})
This emit is not from from flask.ext.socketio import SocketIO, send, but instead called on your socketio variable from socketio = SocketIO(app). Had you done socketio_connection = SocketIO(app), then you'd be calling socketio_connection.emit() to broadcast your data.

Categories

Resources