Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

429 - to many requests #2248

Closed
Gemorroj opened this issue Jan 8, 2019 · 2 comments · Fixed by #2287
Closed

429 - to many requests #2248

Gemorroj opened this issue Jan 8, 2019 · 2 comments · Fixed by #2287

Comments

@Gemorroj
Copy link

Gemorroj commented Jan 8, 2019

Guzzle version(s) affected: 6.3.3

Description
It creates a lot of connections per host.

How to reproduce
https://gist.github.com/Gemorroj/97df5b1d3a50534dfa6fc21ae7f41813

debug mode says (As far as I understand, a new connection is created for each request):

* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
* Found bundle for host api.tempo.io: 0x1340edbe300 [serially]
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Hostname 'api.tempo.io' was found in DNS cache
*   Trying 52.72.73.251...
* TCP_NODELAY set
* Connected to api.tempo.io (52.72.73.251) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#3)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#4)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#5)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#6)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#7)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#8)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#9)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#10)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#11)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#12)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#13)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#14)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#15)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#16)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#17)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#18)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#19)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#20)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#21)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#22)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#23)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#24)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#1)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* Connected to api.tempo.io (52.72.73.251) port 443 (#2)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: s:/ospanel/modules/php/PHP-7.2-x64/cacert.pem
  CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=app.tempo.io
*  start date: Dec  8 00:00:00 2018 GMT
*  expire date: Jan  8 12:00:00 2020 GMT
*  subjectAltName: host "api.tempo.io" matched cert's "api.tempo.io"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
> GET /2/worklogs/issue/SITE-1593?limit=1000 HTTP/1.1
Host: api.tempo.io
Accept-Encoding: gzip,deflate
User-Agent: amasty-report
Authorization: Bearer xxx

As a result, because of the many connections I get 429 error.
For comparison, the code on js works in one connection.

'use strict';

function httpGet(url) {
  return new Promise(function(resolve, reject) {

    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.setRequestHeader('Authorization', 'Bearer xxx');

    xhr.onload = function() {
      if (this.status == 200) {
        resolve(this.response);
      } else {
        var error = new Error(this.statusText);
        error.code = this.status;
        reject(error);
      }
    };

    xhr.onerror = function() {
      reject(new Error("Network Error"));
    };

    xhr.send();
  });
}

let urls = [
  'https://api.tempo.io/2/worklogs/issue/SITE-1593',
  'https://api.tempo.io/2/worklogs/issue/SITE-1517',
  'https://api.tempo.io/2/worklogs/issue/SITE-1500',
  'https://api.tempo.io/2/worklogs/issue/SITE-1484',
  'https://api.tempo.io/2/worklogs/issue/SITE-1466',
  'https://api.tempo.io/2/worklogs/issue/SITE-1430',
  'https://api.tempo.io/2/worklogs/issue/SITE-1287',
  'https://api.tempo.io/2/worklogs/issue/SITE-1277',
  'https://api.tempo.io/2/worklogs/issue/SITE-1275',
  'https://api.tempo.io/2/worklogs/issue/SITE-1266',
  'https://api.tempo.io/2/worklogs/issue/SITE-1255',
  'https://api.tempo.io/2/worklogs/issue/SITE-1230',
  'https://api.tempo.io/2/worklogs/issue/SITE-1209',
  'https://api.tempo.io/2/worklogs/issue/SITE-1202',
  'https://api.tempo.io/2/worklogs/issue/SITE-1201',
  'https://api.tempo.io/2/worklogs/issue/SITE-1186',
  'https://api.tempo.io/2/worklogs/issue/SITE-1033',
  'https://api.tempo.io/2/worklogs/issue/SITE-984',
  'https://api.tempo.io/2/worklogs/issue/SITE-927',
  'https://api.tempo.io/2/worklogs/issue/SITE-683',
  'https://api.tempo.io/2/worklogs/issue/SITE-241',
  'https://api.tempo.io/2/worklogs/issue/SITE-199',
  'https://api.tempo.io/2/worklogs/issue/SITE-174',
  'https://api.tempo.io/2/worklogs/issue/SITE-172',
  'https://api.tempo.io/2/worklogs/issue/SITE-78',
];

Promise.all(urls.map(httpGet))
  .then(
    results => {
      console.log(results);
    },
    error => {
      console.log(error);
    }
  );
@Gemorroj
Copy link
Author

Gemorroj commented Jan 8, 2019

http://php.net/manual/en/function.curl-multi-setopt.php#refsect1-function.curl-multi-setopt-parameters
It doesn't work for some reason.

$httpClient = new Client([
    'handler' => new \GuzzleHttp\Handler\CurlMultiHandler(),
    'curl' => [
        \CURLMOPT_MAX_HOST_CONNECTIONS => 1,
    ],
    'base_uri' => 'https://api.tempo.io',
    'headers' => [
        'Accept-Encoding' => 'gzip,deflate',
        'User-Agent' => 'amasty-report',
        'Authorization' => 'Bearer !!!SECRET-TOKEN!!!', //add your token
    ],
]);

@Gemorroj
Copy link
Author

Gemorroj commented Jan 8, 2019

see https://curl.haxx.se/libcurl/c/CURLMOPT_MAX_HOST_CONNECTIONS.html
I think we need to add the ability to configure curl_multi.
https://github.com/guzzle/guzzle/blob/master/src/Handler/CurlMultiHandler.php#L50-L54
i changed this to:

        if ($name === '_mh') {
            $this->_mh = curl_multi_init();
            curl_multi_setopt($this->_mh, CURLMOPT_MAX_HOST_CONNECTIONS, 5);
            curl_multi_setopt($this->_mh, CURLMOPT_PIPELINING, 1);
            return $this->_mh;
        }

debug:

* Found bundle for host api.tempo.io: 0x202bcdfc7c0 [serially]
* Server doesn't support multi-use (yet)
* Found bundle for host api.tempo.io: 0x202bcdfc7c0 [serially]
* Server doesn't support multi-use (yet)
* Found bundle for host api.tempo.io: 0x202bcdfc7c0 [serially]
* Server doesn't support multi-use (yet)
* Found bundle for host api.tempo.io: 0x202bcdfc7c0 [serially]
* Server doesn't support multi-use (yet)
* Found bundle for host api.tempo.io: 0x202bcdfc7c0 [serially]
* Server doesn't support multi-use (yet)
* No more connections allowed to host: 5
* No connections available.
* Found bundle for host api.tempo.io: 0x202bcdfc7c0 [serially]
* Server doesn't support multi-use (yet)
* No more connections allowed to host: 5

but no more 429 error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant