This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 4 years ago.
I'm trying to build reply bot by using line api and python 2.7.15 .
this is my code
from flask import Flask, request, abort
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage,)
app = Flask(__name__)
line_bot_api = LineBotApi('UIXwXWExxxxxxxxxxxxxxxxxxxxxxxxxxxx')
handler = WebhookHandler('458033a97c124xxxxxxxxxxxxxxxxxxxxx')
number = 1
#app.route("/")
def hello():
return str(number)
#app.route("/webhook", methods=['POST'])
def webhook():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
#handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
text = event.message.text
user_id = event.source.user_id
if(text == 'inc'):
#set global variable here
number += 1
line_bot_api.push_message(user_id,TextSendMessage(text=str(number)))
if __name__ == "__main__":
app.run()
then i implement this on heroku and i try chatting with my bot,
first i send messageinc, he reply me 2
then i try send inc once again ,he reply me 3 and i try again he replies me 1
i try send inc once again he reply me 4
what wrong? why my number doesn't continue?
Python backend apps are typically deployed in multiprocess configuration (the front server - apache, ngnix or whatever - runs multiple parallel processes to handle incoming requests), and any request can be served by any process. Global variables are per-process, so which state you will find your global depends on which process served the request. Conclusion: don't use global variables to store application state - use a shared database (of any kind, it doesn't have to be a SQL database, it just have to be shared amongst all processes).
Related
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 3 years ago.
I have a small flask API setup as following,
from flask import Flask, request, jsonify, Response
import json
import subprocess
import os
app = Flask(__name__)
shellScripts = {
'redeploy': ['/bin/bash', 'redeploy.sh'],
'script-exec': ['/bin/bash', 'script-exec.sh']
}
def prepareShellCommand(json_data, scriptKey):
script=shellScripts[scriptKey]
print('script is')
print(script)
for key in json_data:
if scriptKey == 'redeploy':
script.append("-{0}".format(key[0]))
script.append(json_data[key])
return script
#app.route('/redeploy', methods=['POST'])
def setup_redeploy():
branches_data_json = request.get_json()
if ('frontendBranch' not in branches_data_json and 'backendBranch' not in branches_data_json):
return jsonify({'error': 'Need to provide at least one branch'}), 400
command = prepareShellCommand(branches_data_json, 'redeploy')
sp = subprocess.Popen(command)
return jsonify({'message': 'Redeployment under process'}), 201
#app.route('/execute', methods=['POST'])
def execute_script():
script_data_json = request.get_json()
if ('scriptPath' not in script_data_json):
return jsonify({'error': 'Need to provide script path'}), 400
command = prepareShellCommand(script_data_json, 'script-exec')
sp = subprocess.Popen(command)
return jsonify({'message': 'Script execution under process'}), 201
What's happening is, say I initiate an API endpoint, /execute with some data as {scriptPath: 'some-file'}, and it runs successfully. However, sometimes, regardless of change in the request body data, the API seems to work with the old data, {scriptPath: 'some-file'}, even if I am initiating the API with something like {scriptPath: 'new-file'}. And it doesn't change until I kill the python process, and restart it.
What could be the reason for this? I am running this as a development server, on a google cloud instance.
It's happening with both the endpoints, and I have a gut feeling that it's got something to do with either the subprocess or the dictionary that contains the boilerplate.
Can anyone help me with this?
This is almost certainly because you have defined shellScripts at module level but modify it from your handlers. The changes to the values of that dictionary will persist for the lifetime of the server process.
You should copy the value and modify that instead:
def prepareShellCommand(json_data, scriptKey):
script = shellScripts[scriptKey].copy()
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 4 years ago.
I'm creating a game on Flask and want to have a counter across the entire session. I put together some psuedo code for the general outline of the project. Basically it's a script that pulls a random question from a database, collects user input, returns the correct answer, and then starts over again at the user input route. I want to add a counter that will appears regardless of the function of route. I looked into Flask sessions, but it was confusing where or how to implement... any thoughts/ suggestions? Sessions or otherwise?
get_db_info():
connects to a database
#app.route('/questions')
def user_input():
collects user input and puts into variable
#app.route('/answers')
def results():
if user input = results:
print(correct!)
elif:
print(incorrect)
renders back to user_input()
You already mention sessions, I think they are the solution to your problem:
Flask-Session is an extension for Flask that adds support for
Server-side Session to your application.
Here is an example of doing this with a session. It stores three counters, one for total accesses to the app and two for accesses to individual routes. If you call /A three times and then /B, it will give you
accessed B 1 times, accessed app 4 times
from flask import Flask, session
from flask_session import Session
app = Flask(__name__)
# Check Configuration section for more details
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
#app.route('/')
def reset():
session["counterA"]=0
session["counterB"]=0
session["counterTotal"]=0
return "all counters were reset"
#app.route('/A')
def routeA():
if not "counterA" in session:
session["counterA"]=0
if not "counterTotal" in session:
session["counterTotal"]=0
session["counterA"]+=1
session["counterTotal"]+=1
return "accessed A {} times, accessed app {} times".format(session["counterA"], session["counterTotal"])
#app.route('/B')
def routeB():
if not "counterB" in session:
session["counterB"] = 0
if not "counterTotal" in session:
session["counterTotal"] = 0
session["counterB"] += 1
session["counterTotal"] += 1
return "accessed B {} times, accessed app {} times".format(session["counterB"], session["counterTotal"])
if __name__ == '__main__':
app.run()
The session behaves like a dictionary and is available across all routes. You can simply put your counter there.
For the sake of completeness, a solution without sessions is also possible:
In principle, the flask routes behave just like python functions.
So the following will work:
counter = 0
#app.route('/questions')
def user_input():
global counter
print(counter)
counter+=1
#app.route('/answers')
def results():
global counter
print(counter)
counter+=1
I would discourage the use of globals, they can make your code very hard to read and are not thread safe.
This question already has answers here:
Why does running the Flask dev server run itself twice?
(7 answers)
Closed 5 years ago.
i have some that should not execute again when reload flask
it should be work only once even reload flash
from flask import *
from wxpy import *
app = Flask(__name__)
bot = None
#app.route('/')
def hello_world():
return 'hi,my hello ,iiiHello wxpy! not reload bot'
#app.route('/hello/')
def hello():
return "hello"
#app.route('/friends/')
def hellos():
guys = bot.friends()
return render_template('hello.html', guys=guys)
def init_bot():
bot = Bot(console_qr = 1)
return bot
if __name__ == '__main__':
bot = init_bot()
app.run(debug=True,use_reloader=False)
i just use wxpy and flask to write webs
i want to reload flask auto
but i do not want to execute the Bot init funciton again,for a i need to scan qr-code
any one can help me
i can modiy code and take effect immediately but do not need to scan qr-code again
I am expanding my comment to an answer.
Create a file to flag that bot has been initiated.
import os.path
def init_bot():
bot = Bot(console_qr = 1)
# create an empty file to denote that bot has been initiated
open('bot.initiated', 'a').close()
return bot
if __name__ == '__main__':
if not os.path.exits('bot.initiated'):
bot = init_bot()
app.run(debug=True)
Caveat:
This works only for situation where you are developing and would like to prevent some action during reloads. If you really want to stop the dev-server and initialise the app from the beginning including init_bot, then you should remove the dummy file bot.initiated manually from your system.
For a while now I am trying to learn how to use Ajax with Flask. On the official website of flask there is an example:
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/_add_numbers')
def add_numbers():
a = request.args.get('a', 0, type=int)
b = request.args.get('b', 0, type=int)
return jsonify(result=a + b)
#app.route('/')
def index():
return render_template('index.html')
It works for me well. But I am looking for the following program:
a jQuery code sends an initial number to the python app
the python app stores the number and responds 'received: [the number]'
while true: the python app waits for requests 'increase' for which it adds 1 to the number and returns it
The jQuery part doesn't matter, I can do that but I am not sure how to implement the python part:
#app.route('/_inc_number')
def inc_number():
n = request.args.get('n', 0, type=int)
while true:
req = request.args.get('req', 0, type=string)
if req == 'increase':
n = n + 1
return n #It exits the function. how respond without quit?
Please explain me how I can data back? I am new to both Ajax and Flask too, and I suspect that it is not "real" ajax...Is that right? How would you implement a simple function with the same functionality in flask?
I think what you are missing is that each time the client requests a number increase there is an independent request. Your inc_number handler would be coded as follows:
#app.route('/_inc_number')
def inc_number():
n = request.args.get('n', 0, type=int)
n = n + 1
return n
Then from the jQuery side you have to invoke an independent Ajax request each time you want to increase the number.
Note that with this type of solution the jQuery app is the one that keeps track of the current value of the counter, and it has to send it to Flask with each request. Another possibility would be to have the Flask side remember the number in a user session. For that type of solution your Flask app would have two view functions:
from flask import session
# you need to set a SECRET_KEY in configuration, used to sign the user session
#app.route('/set_number')
def set_number():
# store n in the user session
session['n'] = request.args.get('n', 0, type=int)
#app.route('/inc_number')
def inc_number():
session['n'] = session['n'] + 1
return session['n']
With this solution now jQuery can set the number and not have to send it every time when it invokes inc_number.
I hope this helps.
HTTP requests don't have a memory, they are independent of each other. It means when your Python app gets a request, it does something, sends a response immediately and quits. That's the nature of HTTP.
If you want something persistent (like your number) that lives through more requests, you need:
Persistent storage on the server. It can be a file, a database, or in case of Flask simply an object (variable) in memory.
Identify the user between separate requests. That's what session handling and cookies are for.
A very primitive method (shouldn't be used on production system):
persistent storage: create a global dict (called num) in main()
in index():
create a random session identifier (si)
set num[si] = 0
send si as a cookie
in inc_number() use si from cookie (sent back by the browser) to increase the appropriate num[si]
I'm new to python and wondering if it is possible using BaseHTTPServer to store a global var that is accessible to all requests? Basically I have an async process that requires a POST back into the server as a separate request from the original request, that I would like to write back through to the original request, via a token I'd generate.
No.
To maintain state, you'll need a web framework that supports global variables across requests, or some kind of session management.
Flask is super easy to get up and running and has sessions available.
import flask
app = flask.Flask(__name__)
#app.route('/')
def index():
flask.session['post_token'] = MakeToken()
return '...Content...'
#app.route('/poster', methods=['POST'])
def poster():
if flask.session['post_token']:
DO STUFF HERE
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jxxxRT'