19

I'm building a front-end in angular that is accessing a flask/python RESTful API. I'm using AngularJS v1.2.16.

For some reason, it takes an insane amount of time before the REST resource is loaded, with most of the time just waiting. It's my understanding that 'waiting' is measuring the time to first byte - all my services run locally (the frontend, API and database).

Angular, the API and the Mongo DB are all running locally.

Given that the services all run locally, I am at a loss how to debug this. Does anybody have any tips on where to look? I checked all my methods and they run decently fast (under 100ms per REST call). When I use postman, the API returns near-instantly.

Any ideas how to fix the wait, it only seems to be the case when loading the RESTful resource via angular. The angular $http get request is fairly straight forward:

myAppControllers.controller('ManageCtrl', ['$scope', '$http',
    function($scope, $http) {
        $http({
            url: 'http://127.0.0.1:5000/v1/domains/',
            method: "GET",
            headers: { 'Content-Type': 'application/json' },
        }).
        success(function(data, status, headers, config) {
            console.log('login successful');
            console.log(status);
            console.log(data);
        }).
        error(function(data, status, headers, config) {
            console.log('login failed');
        });
    }]);

EDIT:

  • the issue only appears in Google Chrome, regular mode.
  • the GET requests are fast when using incognito mode.
Samir Said
  • 283
  • 1
  • 2
  • 9
  • What is the result if you skip the angular-app and just do a local GET request towards your API? Fast or slow? – JoakimB May 13 '14 at 19:04
  • if I do a local GET request via CURL or postman it's fast (which leads me to believe it must be an angular issue) – Samir Said May 13 '14 at 19:09
  • another thing I just noticed: if I open the angular-app via chrome icognito then all requests get served quickly as well. Normally I have devtools open and the 'disable cache' setting on. – Samir Said May 13 '14 at 19:13
  • can you remove the content type header and see – Arun P Johny May 14 '14 at 01:30
  • Do you by chance have an extension that interferes with the resource loading installed? Try disabling those one by one. – Alexander Pavlov May 15 '14 at 10:10
  • @ArunPJohny tried it with different content types without any affect. I also tried to strip of any header created automatically by $http but still same effect. API call returns instantly in any other browser, so maybe its a Chrome + AngularJS issue? Another thing I noticed is that the first 3 - 4 calls happen instantly, and then it slows down for any subsequent calls. A complete system restart makes the first 3 - 4 calls fast again, before slowing down. – Samir Said May 20 '14 at 04:59
  • @AlexanderPavlov removed all but the barebone angular, still same effect. – Samir Said May 20 '14 at 04:59
  • a complete restart of the client or the server?.. can you monitor the resource usage by chrome... also investigate where the time is consumed on the network request of in the client side processing – Arun P Johny May 20 '14 at 05:06

4 Answers4

23

We had the same problem and after some research the problem is related with the way Chrome uses connections and the default configuration of flask as mono threaded.

Added threaded=true when flask app is started solved the problem:

app.run(threaded=True)
Derlin
  • 9,572
  • 2
  • 32
  • 53
dd.
  • 440
  • 1
  • 4
  • 9
  • 1
    Fix worked for me. Specifically was a problem with Chrome on Win7. Other detail that might help is that I'm using CORS. OSX worked fine. Postman on Win7 worked fine. – Eugene K Aug 11 '15 at 19:30
  • 1
    Here's my guess: after the initial get request to the server, tcp preconnect opens up a second one thinking it would be useful. Then, another get is sent out over the first socket. But flask processes connections serially on a single thread and is still waiting on the preconnected socket to send a request. So sometime later it eventually gives up and closes the preconnect socket and moves on to the actual get request – jhorey Aug 12 '15 at 12:44
  • 2
    Many thanks, it worked for me. I'm using Flask + Flask-CORS, and Chrome + jQuery. In my case the long TTFB (50 seconds or more) would not happen when refreshing the page (I have a data fetching routine fired at page load). – damix911 Mar 12 '16 at 12:14
  • I had a similar problem with python's BaseHTTPServer.HTTPServer. Using the SocketServer.ThreadingMixIn seems to have fixed it. – masterxilo May 05 '16 at 21:22
  • Thank you so much. – Dynite May 16 '17 at 16:55
  • Thanks! That was helpful! Had a same problem with eve. Debugging is now multiple times faster! – ainla May 19 '17 at 09:39
13

I've run into the same issue (Angular frontend running in Chrome and Flask backend). After trying both Angular 1.2.x and 1.3.x, and a billion other permutations, the only "solution" I've found is to run the Flask backend with the Tornado web server (http://www.tornadoweb.org/en/stable/). Other WSGI containers may work, but this is the one I tested.

In your Flask application, paste the following:

from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

if __name__ == '__main__':
  http_server = HTTPServer(WSGIContainer(app))
  http_server.listen(5000)
  IOLoop.instance().start()

You can start your web server by typing:

python myserver.py
jhorey
  • 166
  • 2
  • 5
  • ha, very interesting. I've figured out the problem by installing nginx on the Angular server and proxy all requests. Instead of Angular --> Flask it now does Angular --> proxy request via Nginx --> Flask; that worked as well. I like your solution much better though. – Samir Said Sep 15 '14 at 04:36
  • How does this help? Why is it that going via tornado/proxy (as @SamirSaid suggests) speeds this up? – AncientSwordRage Mar 04 '15 at 11:03
  • Also curious about why this works. For me, the first angular get is slow 10s wait. But after that it is only 20ms for similar uncached requests. – Ouwen Huang Aug 10 '15 at 23:43
  • 2
    The real fix is posted below by @dd. . This accomplishes the same thing because Tornado is probably multithreaded by default, whereas Flask is singlethread by default (no clue why this design decision). – Eugene K Aug 11 '15 at 19:41
0

I am facing now very similar issue. My current solution (acceptable for my chef at this moment :) ), which unfortunately not remove all problems, is to set header:{ 'Content-Type': 'application/json' } to { 'Content-Type': 'text/plain' }. Now only first GET request is crazy slow, any next takes less than 500ms. I am using Restangular on the frontend and wsgiref.simple_server on the backend.

Radek Anuszewski
  • 1,812
  • 8
  • 34
  • 62
0

I wanted to tie this in as well. But

app.run(threaded=True) 

worked for me!

Derlin
  • 9,572
  • 2
  • 32
  • 53
Eric
  • 569
  • 1
  • 7
  • 10
  • I had the same problem, using Chrome (with fetch api) and Flask. Setting threaded=True fixed it. The problem did not occur with Firefox and also did not occur when using Chrome in incognito mode – raduw Jul 26 '18 at 19:10