I have a server serving HTML with nginx, uwsgi and flask. It's a simple webapp. When you refresh a page the webapp makes some API calls elsewhere and then treats the results returned from the APIs and generate the HTML which is then returned.
Now, most of the time is spend waiting for the APIs to respond. Because of this, I'm using gevent to make the API calls and monkey patching etc etc to make it all concurrent. If for every page refresh you need to make 3 API calls, you don't need to wait for the first call to return to initiate the second call. You initiate all three of them, wait for their responses, and then generate the HTML to be returned.
However, a separate question is whether or not the page refreshes from beginning to end are themselves concurrent. To test this I wrote a small concurrent script to make refreshes to my server:
from gevent import monkey monkey.patch_all() import requests, datetime import gevent def call_func(n): before = datetime.datetime.now() print 'initiating call '+str(n),before requests.get('http://examplemyserver.com') after = datetime.datetime.now() print 'finishing call '+str(n),after, after-before gevent_list = [ gevent.spawn(call_func, n=n) for n in range(10) ] gevent.joinall(gevent_list) Here are the results:
initiating call 0 2016-05-04 23:03:49.437540 initiating call 1 2016-05-04 23:03:49.446304 initiating call 2 2016-05-04 23:03:49.447911 initiating call 3 2016-05-04 23:03:49.450232 initiating call 4 2016-05-04 23:03:49.451774 initiating call 5 2016-05-04 23:03:49.453331 initiating call 6 2016-05-04 23:03:49.454759 initiating call 7 2016-05-04 23:03:49.456301 initiating call 8 2016-05-04 23:03:49.457663 initiating call 9 2016-05-04 23:03:49.458981 finishing call 0 2016-05-04 23:03:51.270078 0:00:01.832538 finishing call 6 2016-05-04 23:03:52.169842 0:00:02.715083 finishing call 3 2016-05-04 23:03:52.907892 0:00:03.457660 finishing call 1 2016-05-04 23:03:53.498008 0:00:04.051704 finishing call 8 2016-05-04 23:03:54.150188 0:00:04.692525 finishing call 4 2016-05-04 23:03:55.032089 0:00:05.580315 finishing call 7 2016-05-04 23:03:55.994570 0:00:06.538269 finishing call 2 2016-05-04 23:03:56.659146 0:00:07.211235 finishing call 9 2016-05-04 23:03:57.149156 0:00:07.690175 finishing call 5 2016-05-04 23:03:58.002210 0:00:08.548879 So you see, ten page refreshes are initiated virtually at the same time, however they are returned sequentially with a difference of about 1 second. This suggests that while internally the external API calls are done concurrently, until an HTTP response is given, no new HTTP responses are being accepted.
So, given that most of the webapp time is spent waiting for API responses, how can I make the whole process concurrent? Is it something that I need to change with nginx? With uwsgi? With flask? I have no idea about the architecture of these things.
Thanks.
EDIT 1: Following Rob's idea, I replaced the server to be called with 'http://httpbin.org/delay/1'. This is the result I obtain:
initiating call 0 2016-05-04 23:36:18.697813 initiating call 1 2016-05-04 23:36:18.706510 initiating call 2 2016-05-04 23:36:18.708645 initiating call 3 2016-05-04 23:36:18.711055 initiating call 4 2016-05-04 23:36:18.712679 initiating call 5 2016-05-04 23:36:18.714051 initiating call 6 2016-05-04 23:36:18.715471 initiating call 7 2016-05-04 23:36:18.717015 initiating call 8 2016-05-04 23:36:18.718412 initiating call 9 2016-05-04 23:36:18.720193 finishing call 0 2016-05-04 23:36:20.599483 0:00:01.901670 finishing call 2 2016-05-04 23:36:20.600829 0:00:01.892184 finishing call 8 2016-05-04 23:36:20.611292 0:00:01.892880 finishing call 5 2016-05-04 23:36:20.618842 0:00:01.904791 finishing call 7 2016-05-04 23:36:20.620065 0:00:01.903050 finishing call 6 2016-05-04 23:36:20.621344 0:00:01.905873 finishing call 1 2016-05-04 23:36:20.622407 0:00:01.915897 finishing call 4 2016-05-04 23:36:20.623392 0:00:01.910713 finishing call 9 2016-05-04 23:36:20.624236 0:00:01.904043 finishing call 3 2016-05-04 23:36:20.625075 0:00:01.914020 This is what you'd expect from a server that can take HTTP calls concurrently. So this shows that the above code that I used for the test is correct, and that the problem is indeed on the server. It's not taking HTTP calls concurrently.
EDIT2: I was playing around and checked that the simplest possible flask app has the same behavior as my server, so I'm giving that as my "minimal example"
Consider the following server:
import time from flask import Flask, jsonify app = Flask(__name__) @app.route("/") def hello(): time.sleep(2) return '' if __name__ == "__main__": app.run(host='0.0.0.0', port=80, debug=True) Now connect to it by taking the previous code and pointing it to http://localhost. The result is the following:
initiating call 0 2016-05-04 23:49:12.629250 initiating call 1 2016-05-04 23:49:12.638554 initiating call 2 2016-05-04 23:49:12.643844 initiating call 3 2016-05-04 23:49:12.645630 initiating call 4 2016-05-04 23:49:12.647866 initiating call 5 2016-05-04 23:49:12.649332 initiating call 6 2016-05-04 23:49:12.650853 initiating call 7 2016-05-04 23:49:12.652448 initiating call 8 2016-05-04 23:49:12.653865 initiating call 9 2016-05-04 23:49:12.655348 finishing call 0 2016-05-04 23:49:14.671281 0:00:02.042031 finishing call 1 2016-05-04 23:49:16.673649 0:00:04.035095 finishing call 2 2016-05-04 23:49:18.676576 0:00:06.032732 finishing call 3 2016-05-04 23:49:20.679746 0:00:08.034116 finishing call 4 2016-05-04 23:49:22.681615 0:00:10.033749 finishing call 5 2016-05-04 23:49:24.683817 0:00:12.034485 finishing call 6 2016-05-04 23:49:26.686309 0:00:14.035456 finishing call 7 2016-05-04 23:49:28.688079 0:00:16.035631 finishing call 8 2016-05-04 23:49:30.691382 0:00:18.037517 finishing call 9 2016-05-04 23:49:32.696471 0:00:20.041123 So basically a simple flask webapp does not take HTTP calls concurrently. How can I change this?
http://httpbin.org/delay/1, but otherwise my code is identical to yours. For me, all of the requests lines occur more-or-less simultaneously, there is a 1-sec delay, and all of the response lines occur more-or-less simultaneously.