I have this application that works how I want to but now I want it to grab live data from some virtual machines every 5 minutes. In the code below I have it set to renew every ten seconds just to see if it works but nothing is happening. I am using time.sleep. What else am I missing?
import time
from flask import Flask, render_template
from testapi import grab_cpu
app = Flask(__name__)
starttime = time.time()
while True:
machines =["build05", "build06", "build07","build08", "build09", "build10", "build11", "build12","build14","build15", "winbuild10","winbuild11", "winbuild12", "winbuild13", "wbuild14", "wbuild15", "winbuild16", "winbuild17", "winbuild18"]
cpu_percentage =[grab_cpu("build05"), grab_cpu("build06"),grab_cpu("build07"),
grab_cpu("build08"), grab_cpu("build09"), grab_cpu("build10"), grab_cpu("build11"), grab_cpu("build12"), grab_cpu("build13"), grab_cpu("build14"), grab_cpu("build15"), grab_cpu("winbuild10"), grab_cpu("winbuild11"), grab_cpu("winbuild12"), grab_cpu("winbuild14"), grab_cpu("winbuild15"), grab_cpu("winbuild16"), grab_cpu("winbuild17"), grab_cpu("winbuild18")]
#app.route("/") # this sets the route to this page
def home():
return render_template('testdoc.html', len = len(machines), machines = machines, cpu_percentage = cpu_percentage)
app.run(use_reloader = True, debug = True)
time.sleep(10.0 - ((time.time() - starttime) % 10.0))
Edit (this is an update with the suggestions, it's still not working as i'd like):
Edit 2 more info: I have one file with a function, grab_cpu, that does an api call to a vm and returns the percentage of usage. I have another file called test doc.html which just displays the html. From these responses i'm guessing I need to use some javascript and something with sockets. Can someone please drop a link to point me in the right direction?
import time
from flask import Flask, render_template
from testapi import grab_cpu
app = Flask(__name__)
#app.route("/") # this sets the route to this page
def home():
starttime = time.time()
while True:
machines =["build05", "build06", "build07","build08", "build09", "build10", "build11", "build12","build14","build15", "winbuild10","winbuild11", "winbuild12", "winbuild13", "wbuild14", "wbuild15", "winbuild16", "winbuild17", "winbuild18"]
cpu_percentage =[grab_cpu("build05"), grab_cpu("build06"),grab_cpu("build07"),
grab_cpu("build08"), grab_cpu("build09"), grab_cpu("build10"), grab_cpu("build11"), grab_cpu("build12"), grab_cpu("build13"), grab_cpu("build14"), grab_cpu("build15"), grab_cpu("winbuild10"), grab_cpu("winbuild11"), grab_cpu("winbuild12"), grab_cpu("winbuild14"), grab_cpu("winbuild15"), grab_cpu("winbuild16"), grab_cpu("winbuild17"), grab_cpu("winbuild18")]
return render_template('testdoc.html', len = len(machines), machines = machines, cpu_percentage = cpu_percentage)
time.sleep(10.0 - ((time.time() - starttime) % 10.0))
app.run(use_reloader = True, debug = True)
Here is the page:
Thank you.
I recommend against using Flask to handle the scheduling. The intended flow for Flask requests is:
Receive an HTTP request from the browser
Generate a response as quickly as possible (ideally in a few milliseconds, but almost always less than a few seconds)
Return the response to the browser
The intention of the code above seems to be to use Flask to push updates down to the browser, but Flask can only respond to incoming requests, not force the browser to change.
For the use case you're describing, a simpler solution would be to handle the refresh logic in the browser.
For a very rudimentary example, put this into your testdoc.html template:
<script type="text/javascript">
setTimeout(function () {
location.reload();
}, 10 * 1000);
</script>
That will reload the page every 10 seconds, which will generate a new request to your Flask server and display updated information in your browser.
If you want to get fancier and avoid reloading the entire page, you can use JavaScript XmlHttpRequests or the more modern Fetch API to update specific elements of the page asynchronously.
Also, here's a suggested simplification of the Python code:
from flask import Flask, render_template
from testapi import grab_cpu
app = Flask(__name__)
build_machines = list(map(lambda i: 'build%02d' % i, range(5, 16)))
win_build_machines = list(map(lambda i: 'winbuild%02d' % i, range(10, 19)))
machines = build_machines + win_build_machines
# Handle HTTP GET requests to / route
#app.route("/", methods=['GET'])
def home():
cpu_percentage = list(map(lambda b: grab_cpu(b), machines))
return render_template('testdoc.html', len = len(machines), machines = machines, cpu_percentage = cpu_percentage)
app.run(use_reloader = True, debug = True)
Your code needs some work, Flask views are not meant to be declared inside a loop. I would suggest the following:
Remove the Flask view from inside the while loop.
Declare the server outside the loop too.
Write your code inside a function.
Run the while loop just calling the function to grab the information from your sources.
Based on what I think is just an example made on the run, I will also make some assumptions about your requirement:
This is not exactly your code.
Your code works perfectly, but this implementation is lacking.
Your project has some level of complexity.
You need to show this data somewhere else.
Base on these (and perhaps additional conditions), I would say you have two ways to achieve in an effective way what you need:
(Not recommended) Create a Cron Job and run everything in a dedicated script.
(My favorite) Encapsulate the logic of your script inside a Flask API call, a method, or a function, and declare it as a Celery task, scheduled to run every 5 seconds, updating your database, and use a view with some JS reactivity to show the data in realtime.
I have a Flask app, which is running a web-app to control an alarm. I use apscheduler to trigger a function triggerAlarm() and within that I want to have the logic to actually trigger it, but also I want to have the web-page to display another alarm.html, no matter which site the user is currently on.
The idea is to show the user, that the alarm went off by opening another html page (possibly the main page, which has context dependent text and layout)! Also the page content is outdated after an alarm. The client must reload the page, if the after-alarm info should be displayed/updated.
This is the key problem: in my head it is necessary to redirect every client to the alarm page at this event. Maybe there is a better solution all along. (I don't want to use JavaScript, since I use 4 languages already besides the 3 I use regularly.)
The problem is, that the function itself has no "route" and is not part of the app (this is what I think happens). Also I cannot easily make it a route, since it is activated not by a html request, but by the scheduler.
How can I trigger a function and redirect to a specified page?
*I tried redirect() and RequestRedirect() w/ and w/o url_for() and return render_template('index.html', **templateData) ... but I cannot load the desired page.
The code looks something like this:
from apscheduler.schedulers.background import BackgroundScheduler
# Web Server Gateway WSGI
from flask import Flask, render_template, request, url_for
scheduler = BackgroundScheduler()
scheduler.start()
scheduler.add_job(triggerAlarm,'date',run_date=somedate)
#app.route("/")
def index():
# prepare templateData
return render_template('index.html', **templateData)
def triggerAlarm():
# this doesn't work, since it is called by the scheduler and has no route!
return redirect(url_for("/"))
If you have defined a method, "triggerAlarm()", and want to make it available to a route, then create your route like:
#app.route("/alarm-url")
def web_alarm():
triggerAlarm()
return redirect(url_for("/"))
This will cause the same thing that happens when the scheduler runs triggerAlarm() to happen when a user hits the route /alarm-url, and then return them home.
The takeaway is that you can define methods outside of flask route, in other modules, etc, and then call those methods in a flask route.
Update
If you have to keep triggerAlarm() separate from any routes you could do something like:
class StatusDenied(Exception):
pass
#app.errorhandler(StatusDenied)
def web_alarm(error):
return redirect(url_for("/"))
def triggerAlarm():
...
raise StatusDenied
I really could not find any resource on this. So how can I seperate caching of views/functions than static files (i.e. .css,.js)?
I want to cache my static objects for a week, on the other hand I need to cache functions/views for only a few minutes.
When I do following
from flask.ext.cache import Cache
cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app)
#cache.cached(timeout=500)
def index():
return render_template('index.html')
then all views, objects' cache time is set to the same value, 500. How to go about it?
I would not server the static files from my python application but try to delegate that to the web server (nginx, apache... ).
Then you could set the time to expire through headers controlling how long should the browser cache them.
Variable rules isn't working as I'd expect when static_url_path is used.
Simply, why does this work:
import flask
app = flask.Flask(__name__)
#app.route("/", defaults={"p": "")
#app.route("/<path:p>")
def main(p):
return "<h1>Hello %s</h1>" % p
if __name__ == '__main__':
app.run(debug=True)
But not this?
import flask
app = flask.Flask(__name__, static_url_path="")
#app.route("/", defaults={"p": "")
#app.route("/<path:p>")
def main(p):
return "<h1>Hello %s</h1>" % p
if __name__ == '__main__':
app.run(debug=True)
Note the added static_url_path
Some background details; I'm new to both Flask and AngularJS, but are using them here in conjunction with each other and for those not familiar with AngularJS; I'm using AngularJS to produce a single-page application in which paths are used for dynamically replacing content within a document, as opposed to reloading the whole page. Thus, I need all paths routed to the same html document (not included in the above example), ideally coming form the same function, so as to let AngularJS handle rendering as opposed to Flask.
The below answer solved that issue, but it isn't working when status_url_path is used, and I can't figure out why.
Flask route for AngularJS with HTML5 URL mode
Adding this for reference, as he is doing this exact thing.
http://www.youtube.com/watch?v=2geC50roans
You are effectively telling Flask to map /<path:static_path> to static files. That means that everything is now considered static. Don't do this!
Angular pages don't need to call into Flask static routes; keep your static routes under /static, have / produce your Angular application, then use other routes to handle Angular AJAX calls. These can have proper paths; Angular doesn't dictate what routes your Flask server will respond to.
Then keep your static route to serve the JavaScript and CSS and images, e.g. the actual static content referenced from your HTML page.
I am new to web development just pieced together my first django web app and integrated with apache using mod_wsgi.
the app has some 15 parameters on which you could query multiple SQL server databases and the result can be downloaded as .xls file; have deployed the same on the company network.
the problem is when i access the web app on one machine and set query parameters, the same parameters get set in the web app when i try opening it from a different machine (web client) .
Its like there is just one global object which is being served to all the web client.
Am using django template tags to set values in the app's html pages.
not using any models in the django project as am querying SQL server DB which are already built.
the query function from my views.py looks like
def query(self,request):
"""
"""
print "\n\n\t inside QUERY PAGE:",request.method,"\n\n"
self.SummaryOfResults_list = []
if self.vmd_cursor != -1:
self.vmd_cursor.close()
if request.method == 'POST':
QueryPage_post_dic = request.POST
print "\n\nQueryPage_post_dic :",QueryPage_post_dic
self.err_list = []
self.err_list = db_qry.validate_entry(QueryPage_post_dic)
if len(self.err_list):
return HttpResponseRedirect('/error/')
else:
channel_numbers,JPEG_Over_HTTP,Codec,format,rate_ctrl,transport,img_sz,BuildInfo_versions, self.numspinner_values_dic = db_qry.process_postdata(QueryPage_post_dic, self.numspinner_values_dic)
return self.get_result(request,channel_numbers,JPEG_Over_HTTP,Codec,format,rate_ctrl,transport,img_sz,BuildInfo_versions)
else:
print "\nself.Cam_Selected_list inside qry :",self.Cam_Selected_list
if (len(self.Cam_Selected_list) != 1):
return HttpResponseRedirect('/error/')
self.tc_dic,self.chnl_dic,self.enbl_dic,self.frmt_dic,self.cdectyp_dic,self.imgsz_dic,self.rtctrl_dic,self.jpg_ovr_http_dic,self.trnsprt_dic,self.cdec_dic,self.typ_dic,self.resolution_dic, self.vmd_cursor = populate_tbls.Read_RefTbls(self.Cam_Selected_list[0])
c = self.get_the_choices(self.Cam_Selected_list[0])
c['camera_type']= self.Cam_Selected_list[0]
for k,v in self.numspinner_values_dic.items():
c[k] = v
self.vmd_cursor.execute("SELECT DISTINCT [GD Build Info] FROM MAIN")
res_versions = self.vmd_cursor.fetchall()
version_list = []
ver_list = ['',' ']
for version in res_versions:
tmp_ver = version[0].encode()
if (tmp_ver not in ver_list):
version_list.append(tmp_ver)
c['build_info'] = version_list
print "\n\n c dic :",c
c.update(csrf(request))
return render_to_response('DBQuery.html',c)
and the dictionary being passed to render_to_response holds the values that setting checkboxes and multiselect boxes (dojo)
thanks
Its like there is just one global object which is being served to all the web client.
What you're saying is probably exactly what's happening. Unless you're building whatever object that self in that example code is anew for each request, it will be practically randomly shared between clients.
You can store your global variable in SQL DB that you are using. This way you can retain the value/state of the variable across request -> response cycle.
If you need faster response time explore Key->Value Pair in memory datastore like redis.
To add to what's mentioned by AKX I suggest that you read up on HTTP Request -> HTTP Response cycle and How web applications work.