Reputation: 47
What I want to do: I have built a dashboard which shows Key Performance Indicators that I get from an API at Zendesk.com. It needs to update at regular intervals (I am trying to use time.sleep() to accomplish this) but it cannot be too often as I have a 700 request per minute limit. I used Django so I could create an interface to show the data. IT WILL NEVER BE USED AS A WEBSITE.
The problem: I use jquery "get" calls to get data from my script. If I use "python manage.py runserver" it eventually creates what I am guessing are many many workers and makes calls to my script far far too often and blows past my 700 request limit with Zendesk. If I use "python manage.py runserver --nothreading" it works great HOWEVER when I click a button in the navbar or try to refresh the page, I have to wait for my script to run fully before it gets to the task.
Relevant code of my program:
As an example, in the html code I call data from json:
<script type="text/javascript">
$(document).ready(function() {
function pollSiteData () {
$.get('/nb_new/', function(resp) {
$('#nb_new').text(resp['nb_new']);
});
window.setTimeout(pollSiteData,10000);
}
pollSiteData();
});
</script>
Which calls into a class based view:
url(r'^nb_new/',views.SiteNumberView.as_view())
The view is as follows(the xxxxxx is my login information for testing purposes):
class SiteNumberView(views.APIView):
def get(self, request, *args, **kwargs):
data = engine.main("xxxxx","xxxxxx","xxxxxx")
return JsonResponse(data)
The above class based view calls the function "main" from a file engine.py that I made.
The function is:
def main(*args):
client = ZenClient(args)
time.sleep(45)
print("Next iteration")
return get_infos(client, "open", "pending", "new")
the Main function call get_infos which returns a dictonary that I convert to json.
def get_infos(client, status, status2, status3):
#Script that downloads stats from Zendesk
return {"nb_new": str(len(filtered_new_tickets))}
When I run "python manage.py runserver" we can see that it is using my script far too often:
Next iteration
Next iteration
Next iteration
[09/May/2018 08:01:21] "GET /nb_new/ HTTP/1.1" 200 86
Next iteration
[09/May/2018 08:01:30] "GET /nb_new/ HTTP/1.1" 200 86
Next iteration
[09/May/2018 08:01:35] "GET /nb_new/ HTTP/1.1" 200 86
Next iteration
[09/May/2018 08:01:51] "GET /nb_new/ HTTP/1.1" 200 86
[09/May/2018 08:02:04] "GET /nb_new/ HTTP/1.1" 200 86
Next iteration
When I use "python manage.py runserver --nothreading" it makes calls at good intervals but buttons on the interface are non responsive. (I imagine because it has to finish the script before it can acknowledge a button press.)
Here is a picture of my interface ("nb_new" updates the number of tickets next to "support needs response")
Conclusion/Question: How can I make sure that my script is only running lets say once every minute and 15 seconds but still let the interface respond to a button push or refresh the page? Please try to avoid giving solutions that would require me to use an entirely different framework. Time is a very scarce resource unfortunately.
Upvotes: 0
Views: 1873
Reputation: 21734
Here's a simple solution:
The easier way to store the new updates will be to create a dedicated model just for this data. Create one instance of this model and just keep updating its state (field values) whenever new data arrives instead of creating a separate object everytime. Then from you view, whenever you get a jQuery call, you can return this object.
If you don't like using this model-and-database approach, you can use a memory based database (queue) to store the data from your script and then access it from your Django view. I recommend Redis for this.
Example script:
# start_server.py
import subprocess
import threading
import time
def ping():
while True:
print("Pinging ...") # do actual API pinging stuff here
time.sleep(10)
t = threading.Thread(target=ping)
t.start() # this will run the `ping` function in a separate thread
# now start the django server
subprocess.call(['python', 'manage.py', 'runserver'])
Now, all you have to do is run python start_server.py
and it will automatically run the Django server as well as the API ping function.
Upvotes: 1