Can I handle POST requests to Flask server in background thread? - python

I know how to receive data from POST request in main thread:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/", methods=['POST'])
def parse_request():
my_value = request.form.get('value_key')
print(my_value)
return render_template("index.html")
But can I do that in background thread to avoid blocking UI (rendering index.html)?

I'm assuming you want the html rendering and processing of your request to run concurrently. So, you can try threading in Python https://realpython.com/intro-to-python-threading/.
Let say you have a function that performs some processing on the request value, You can try this:
from threading import Thread
from flask import Flask, render_template, request
def process_value(val):
output = val * 10
return output
app = Flask(__name__)
#app.route("/", methods=['POST'])
def parse_request():
my_value = request.form.get('value_key')
req_thread = Thread(target=process_value(my_value))
req_thread.start()
print(my_value)
return render_template("index.html")
Thread will allow process_value to run in the background

Related

How to make a server-side loop endless and non-blocking at the same time without using threading/background jobs?

I need an endless loop to run server-side and emit some information per iteration.
Also, I need to make sure it is started only once - preferably on server start-up - and not induced by various users using the app.
Then I would like to avoid additional stack (threading, background jobs etc.) if possible.
Here is the task:
#app.route('/refresh_games_list_periodically')
def refresh_games_list_periodically():
while True:
response = {
'games_list': games_manager.get_nonexpired_games(),
}
socketio.emit('games_list_refreshed', response)
time.sleep(1)
It starts whenever 'index.html' is rendered:
#app.route('/')
def index():
return render_template('index.html')
index.html:
fetch("{{url_for('refresh_games_list_periodically') }}")
Full code:
import time
from flask import (
Flask,
render_template,
jsonify,
request,
)
from flask_socketio import SocketIO, emit
from minesweeper import Game, GamesManager
games_manager = GamesManager()
app = Flask(__name__)
socketio = SocketIO(app)
#app.route('/refresh_games_list_periodically')
def refresh_games_list_periodically():
while True:
response = {
'games_list': games_manager.get_nonexpired_games(),
}
socketio.emit('games_list_refreshed', response)
time.sleep(1)
#app.route('/')
def index():
return render_template('index.html')
The problem currently is that whenever a new user enters 'index.html', another iteration of the loop will start running besides the old one.
I have tried using some boolean flags to mark the view as already called, but could not get it right in Flask context.
Then I thought I could make refresh_games_list_periodically a normal function, not a view, and just call it in my Flask app before views. But then the while loop will be blocking and no page will be rendered:
import time
from flask import (
Flask,
render_template,
jsonify,
request,
)
from flask_socketio import SocketIO, emit
from minesweeper import Game, GamesManager
games_manager = GamesManager()
app = Flask(__name__)
socketio = SocketIO(app)
refresh_games_list_periodically()
def refresh_games_list_periodically():
while True: # WILL BLOCK
response = {
'games_list': games_manager.get_nonexpired_games(),
}
socketio.emit('games_list_refreshed', response)
time.sleep(1)
#app.route('/')
def index():
return render_template('index.html')
How else can I do this?
thread = threading.Thread(target=refresh_games_list_periodically)
thread.start()
I guess ... I imagine this is not a great idea however and you are probably better off running your socket loop in one process and your flask app seperately

How can I add webhook events to a flask server?

I have been searching everywhere for tutorials on how to create and implement webhooks which listen for events within a back-end API. For instance, if I had a server written in python flask, how would I listen to server-side events (example: user has created 100 total records) which then executes some more back-end code or requests external data?
from flask import Flask
app = Flask(__name__)
#app.route('/')
def index():
return {"status": 200}
#Some webhook code listening for events in the server
if __name__ == '__main__':
app.run()
What do I write to listen for server events?
You can use flask feature called before_request it like this
from flask import Flask, jsonify, current_app, request
app = Flask(__name__)
#app.before_request
def hook_request():
Flask.custom_variable = {
"message": "hello world",
"header": request.args.get("param", None)
}
#app.route('/')
def home():
variable = current_app.custom_variable
return jsonify({
"variable": variable,
})
if __name__ == '__main__':
app.run()
and to test it
like this
→ curl http://localhost:5000/
{"message":"hello world"}
→ curl http://localhost:5000\?param\=example
{"variable":{"header":"example","message":"hello world"}}

How to run flask request as asynchronous form with uwsgi?

I have one flask application 'merge.py'. From this I am calling two request and getting their response as:
from flask import Flask
from flask import request, jsonify
import json
import time
import requests
app = Flask(__name__)
#app.route('/check')
def check_working():
result_1 = requests.get('http://0.0.0.0:8080/hello').content
result_2 = requests.get('http://0.0.0.0:7000/bye').content
return "True"
if __name__=='__main__':
app.run(debug=True,host='128.7.7.10',threaded=True)
Right now when I am running the above file, both the request '/hello' and '/bye' running synchronously. How I can make them asynchronous with uwsgi. Suppose '/hello' is taking 10sec and '/bye' is taking 5sec, so total time it should take to execute is 10sec not 15sec. I want to collect the output of both the request. How I can achieve the asynchronous behavior here.
Thanks

Flask can't access cookies under #socketio.on when using with Eventlet

I am using Eventlet to do some background emit processes, but now ever since starting to use Eventlet, under every handler under #socketio.on, the request variable does not work as intended. For example, under an ordinary #APP.route('/abc/') I can use request.cookies.get('csrf'), etc. But under #socketio.on, request simply isn't the same. request.cookies.get('...') returns None every time.
import json
import os
import time
import eventlet
import gamble
import eng_puzzle
import authentication
import gcaptchacheck
from flask import Flask, redirect, url_for, request, render_template, make_response
from flask_compress import Compress
from flask_socketio import SocketIO, send, emit
from flask_sslify import SSLify
from store import REDISDB
eventlet.monkey_patch()
These are the imports.
def bg_emit():
"""Background emit"""
currentpotinfo = json.loads(REDISDB.get('potinfo').decode('UTF-8'))
pot_info = {
'id': currentpotinfo['id'],
'endtime': currentpotinfo['starttime'] + 30 - int(time.time()),
'hashwin': currentpotinfo['hashwin'],
'message': 'Entries closing in: ',
'winner': 'Not yet chosen'
}
socketio.emit('infoupdate', {'info': pot_info}, broadcast=True)
Background emit function (above)
def testemit():
"""test"""
while True:
bg_emit()
eventlet.sleep(1)
How it is called (above)
APP = Flask(__name__)
Compress(APP)
socketio = SocketIO(APP)
Defining APP and socketio (above)
if __name__ == '__main__':
print('RUN')
eventlet.spawn(testemit)
try:
socketio.run(APP, port=80, debug=True)
except PermissionError:
HPORT = int(os.environ.get('PORT'))
socketio.run(APP, port=HPORT, debug=False)
How the server is run. The except is just for deployment. (above)
#socketio.on('pot')
def handle_message(message):
"""Handle messages"""
print(message)
user = authentication.checksession(request)
print('user', user)
print(request.cookies.get('csrf'))
if user and request.cookies.get('csrf') == message.get('csrf'):
One of the places that are having trouble. authentication is a custom script for authentication site wide. There are debug messages and they prove that None is returned every time a cookie is called. How can I get around this issue? Is there a solve to the issue itself or do I have to make my own way around it?

Trouble with accessing flask-socketio session

When I run my local application with flask-socketio I can access session using from flask import session, but when I run it with gunicorn on server (gunicorn --worker-class eventlet -w 1 app:app) it return me session.keys() as Array[0].
How could I fix it to establish this local-proxy with session on server?
Thanks
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#app.before_request
def before_request():
session['key_1'] = 'Hello,'
session['key_2'] = 'World'
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('connect', namespace='/')
def socket_connect():
session_keys = session.keys()
emit('connect response', {
'session_keys': session_keys
})
#socketio.on('disconnect', namespace='/')
def socket_disconnect():
print('Client disconnected', request.sid)
if __name__ == '__main__':
socketio.run(app)
I found a solution.
Session was dissapearing and could not be shared to socketio, because I added redirect page rules on cloudflare for my domain.
When I changed Forwarding type of all rules to 302 - Temporary everything worked well.

Categories

Resources