How to pass variable to the Flask function while using threading? - python

I want to create multiple threads and every one of them should create flask app.
I am not sure how to do it, but that's what I have:
app = Flask(__name__)
app.url_map.strict_slashes = False
#app.route('/api/v1/something/<string:FirstArgument>/<string:SecondArgument>/', methods=['POST'])
def do_it(FirstArgument, SecondArgument):
request_str = request.get_data().decode('utf-8').strip()
response = somefunction(mydata.state, request_str)
return response, 200
def run_app(this_port, mydata):
currentThread = threading.current_thread()
mydata.state = some_function_that_returns_6GB_of_data()
app.run(host='0.0.0.0',port=this_port)
if __name__ == '__main__':
mydata = threading.local()
thread1 = Thread(target=run_app, args=(4100, mydata,))
#thread2 = Thread(target=run_app, args=(4101,mydata,))
thread1.start()
#thread2.start()
For now I want to test only one thread. And I don't know how to pass mydata.state to the 'do_it'. If I add new argument (def do_it(FirstArgument, SecondArgument, mydata.state)) than Flask says that he wants to get this variable from the app.route. How can I pass this data to the do_it function?
And one more question. This program will pas N instances of state to N threads on N ports?
Or I should do something like this:
def do_it(FirstArgument, SecondArgument):
request_str = request.get_data().decode('utf-8').strip()
response = somefunction(mydata.state[threading.get_ident()], request_str)
return response, 200
def run_app(this_port, mydata):
currentThread = threading.current_thread()
mydata.state[threading.get_ident()] = some_function_that_returns_6GB_of_data()
app.run(host='0.0.0.0',port=this_port)

Related

Python Flask infinite loop use global list which can be extended

I would like to run an infinite loop in flask, which do something with a global list.
I'd like to append the list through an API call, and process data from the updated list.
What is the problem?
Usage: you run flask application, and call localhost:5000/ to append the list.
It will return the new list, but in the loop, it remains the initial list.
Thanks
import time
from flask import Flask
from multiprocessing import Process, Value
app = Flask(__name__)
stuff = [1, 2]
#app.route('/', methods=['GET'])
def index():
global stuff
stuff.append(max(stuff) + 1)
print('in request, stuff: ', stuff)
return ', '.join(map(str, stuff))
def print_stuff():
global stuff
print('in loop, stuff: ', stuff)
def record_loop(loop_on):
while True:
if loop_on.value == True:
print_stuff()
time.sleep(1)
if __name__ == "__main__":
recording_on = Value('b', True)
p = Process(target=record_loop, args=(recording_on,))
p.start()
app.run(debug=True, use_reloader=False)
p.join()
I found the working solution:
import time
from flask import Flask
from flask_apscheduler import APScheduler
app = Flask(__name__)
scheduler = APScheduler()
i = 0
def scheduleTask():
global i
print("This test runs every 1 seconds", i)
time.sleep(2)
#app.route('/')
def hello():
global i
i += 1
return str(i)
if __name__ == '__main__':
scheduler.add_job(id = 'Scheduled Task', func=scheduleTask, trigger="interval", seconds=1)
scheduler.start()
app.run(host="0.0.0.0")

can't initialize values before starting App in Flask

I'm playing with Flask a little, for my application I would require a global storage which is updated by a Thread running in the background on the server. I found this question about global context and the answer from Johan Gov seems to work if I init the server using /create explicitly:
from flask import Flask
from flask.json import jsonify
app = Flask(__name__)
cache = {}
#app.route("/create")
def create():
cache['foo'] = 0
return jsonify(cache['foo'])
#app.route("/increment")
def increment():
cache['foo'] = cache['foo'] + 1
return jsonify(cache['foo'])
#app.route("/read")
def read():
return jsonify(cache['foo'])
if __name__ == '__main__':
app.run()
If I try to call the init automaticaly however, it fails as apparently no cache["foo"] is known.
from flask import Flask
from flask.json import jsonify
app = Flask(__name__)
cache = {}
def create(): #create does not have a route anymore
cache['foo'] = 0
#app.route("/increment")
def increment():
cache['foo'] = cache['foo'] + 1
return jsonify(cache['foo'])
#app.route("/read")
def read():
return jsonify(cache['foo'])
if __name__ == '__main__':
create() #initialize by default
app.run()
Why is this happening? How can I initialize global state before starting the Application?
You can use the Cache as your app property, i always use this when i want to avoid awkward global definitions, just define the cache like this:
# here u create a "cache" attribute for the app.
app.cache = {}
app.cache['foo'] = 0
# then after that when calling in a route:
# notice that we don't need the global keyword since we are using the app.
#app.route("/increment")
def increment():
app.cache = app.cache + 1
return jsonify(app.cache)
I even used relatively big objects like deep learning models using this method and had not problems at all.
tbh, the above code work for me without any change and I'm able to read and increment counter.
Try below code with global variable
from flask import Flask
from flask.json import jsonify
app = Flask(__name__)
cache = {}
def create(): # create does not have a route anymore
global cache
cache['foo'] = 0
#app.route("/increment")
def increment():
global cache
cache['foo'] = cache['foo'] + 1
return jsonify(cache['foo'])
#app.route("/read")
def read():
return jsonify(cache['foo'])
if __name__ == '__main__':
create() # initialize by default
app.run()

FastAPI and "While True" process

I have some function that is doing stuff in while True (for example just print a str):
class LoopHandler(metaclass=Singleton):
def start_loop(self, phrase: str):
while True:
print(phrase)
time.sleep(1)
And I have a simple FastAPI server running in parallel:
class APIServer(uvicorn.Server):
def install_signal_handlers(self):
pass
#contextlib.contextmanager
def run_in_thread(self):
thread = threading.Thread(target=self.run)
thread.start()
try:
while not self.started:
time.sleep(1e-3)
yield
except KeyboardInterrupt:
self.should_exit = True
thread.join()
And it works fine, text prints, API works.
But the task is to "restart" loop when specific API method is called. Something like this:
#app.get("/get")
async def get():
response = {'response': 'response'}
# restart loop here with LoopHandler().start_loop('another Text')
return response
Thanks for any advice!
My main():
if __name__ == '__main__':
config = uvicorn.Config("api_view:app", log_level="debug")
server = APIServer(config=config)
with server.run_in_thread():
LoopHandler().start_loop('Text')
ADD:
When I call LoopHandler from API, It begin new thread and new LoopHandler instance in it. So, if I add flag, like this:
class LoopHandler(metaclass=Singleton):
def __init__(self, done: bool = False):
self.done = done
def start_loop(self, phrase: str):
while not self.done:
print(phrase)
time.sleep(1)
My console looks like this:
Text
another Text
Text
another Text
Text

How to communicate with multiple servers using the single class defined in python and run it parallel

I have a python class that communicates with a server. That python class has many functions, i was using few functions. But i want to access multiple servers data at same time using the python class i have.
Am trying something like this, but it'll run one after the other. And i wanted to get the data at same time.
import threading
from server_class import server
class runMonitor(threading.Thread):
def __init__(self,func):
self.func = func
threading.Thread.__init__(self)
def run(self):
self.func()
def monitorSB(ipAddr):
sb = server(ipAddr)
sb.readInfo()
print ('\nReading Registers...\n')
sb.read_rx()
sb.read_tx()
i = 0
while(1):
if i == 0:
print 'Monitoring Registers...'
i = 1
sb.monitor_tx()
sb.monitor_rx()
t = runMonitor(monitorSB('192.168.10.78'))
q = runMonitor(monitorSB('192.168.10.101'))
t.start()
q.start()
print ('\nTest Done...\n')
In the above code, i wanted to access both servers at same time. Help me how to run in parallel
The thing is by saying monitorSB('192.168.10.78') it will execute it before passing it to your thread. Try this:
import threading
from server_class import server
class runMonitor(threading.Thread):
def __init__(self,func, param):
self.func = func
self.param = param
threading.Thread.__init__(self)
def run(self):
self.func(self.param)
def monitorSB(ipAddr):
sb = server(ipAddr)
sb.readInfo()
print ('\nReading Registers...\n')
sb.read_rx()
sb.read_tx()
i = 0
while(1):
if i == 0:
print 'Monitoring Registers...'
i = 1
sb.monitor_tx()
sb.monitor_rx()
t = runMonitor(monitorSB, '192.168.10.78')
q = runMonitor(monitorSB, '192.168.10.101')
t.start()
q.start()
print ('\nTest Done...\n')

Define a function in Tornado

Hi all I have this main in Tornado:
def main():
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application())
http_server.listen(options.port)
periodic = tornado.ioloop.PeriodicCallback(check_commands_response, 5000)
periodic.start()
tornado.ioloop.IOLoop.instance().start()
Now, how you can see, I've put in the main a periodic function that calls a function.
In this function I would use some function methods that are into some classes.... so I cannot put this check_commands_response out of the class. But I can't put the function also into the class (it's a BaseHandler) because when the main starts the function isn't already defined...
How can I do?
EDIT
What is wrong if I write this:
class CheckCommandResponse(BaseHandler):
#tornado.web.authenticated
#tornado.web.asynchronous
#tornado.gen.engine
#staticmethod
def check_commands_response(self):
self.lock_tables("read", ['networks'])
nets = self.db.query("SELECT DISTINCT netid from networks")
self.unlock_tables
for net in nets:
got_commands_response(net)
#staticmethod
def got_commands_response(netid):
como_url = "".join("http://xx.xx.xx.xx:44444/ztc_config?netid=" \
+ netid + "&opcode_group=0&opcode=0&start=-10s&end=-1s")
http_client = AsyncHTTPClient()
#asynchronous alternative to time.sleep
yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 5)
response = yield tornado.gen.Task(http_client.fetch, como_url)
print response
################################################################################
# Application Entry Point
################################################################################
def main():
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application())
http_server.listen(options.port)
periodic = tornado.ioloop.PeriodicCallback(CheckCommandResponse.check_commands_response, 5000)
periodic.start()
tornado.ioloop.IOLoop.instance().start()

Categories

Resources