title: Rate-limiting Guzzle Requests in Symfony
body: <p>This actually follows on from a previous question I had that, unfortunately, did not receive any answers so I'm not exactly holding my breath for a response but I understand this can be a bit of a tricky issue to solve.</p>
  
  <p>I am currently trying to implement rate limiting on outgoing requests to an external API to match the limit on their end. I have tried to implement a token bucket library (<a href="https://github.com/bandwidth-throttle/token-bucket" rel="nofollow noreferrer">https://github.com/bandwidth-throttle/token-bucket</a>) into the class we are using to manage Guzzle requests for this particular API.</p>
  
  <p>Initially, this seemed to be working as intended but we have now started seeing 429 responses from the API as it no longer seems to be correctly rate limiting the requests.</p>
  
  <p>I have a feeling what is happening is that the number of tokens in the bucket is now being reset every time the API is called due to how Symfony handles services.</p>
  
  <p>I am setting currently setting up the bucket location, rate and starting amount in the service's constructor:</p>
  
  <pre><code>public function __construct()
  {
    $storage = new FileStorage(__DIR__ . "/api.bucket");
    $rate = new Rate(50, Rate::MINUTE);
    $bucket = new TokenBucket(50, $rate, $storage);
    $this-&gt;consumer = new BlockingConsumer($bucket);
    $bucket-&gt;bootstrap(50);
  }
  </code></pre>
  
  <p>I'm then attempting to consume a token before each request:</p>
  
  <pre><code>public function fetch(): array
  {
    try {
      $this-&gt;consumer-&gt;consume(1);
      $response = $this-&gt;client-&gt;request(
        'GET', $this-&gt;buildQuery(), [
          'query' =&gt; array_merge($this-&gt;params, ['api_key' =&gt; $this-&gt;apiKey]),
          'headers' =&gt; [ 'Content-type' =&gt; 'application/json' ]
        ]
      );
    } catch (ServerException $e) {
      // Process Server Exception
    } catch (ClientException $e) {
      // Process Client Exception
    }
    return $this-&gt;checkResponse($response);
  }
  </code></pre>
  
  <p>I can't see anything obvious in that, that would allow it to request more than 50 times per minute unless the amount of available tokens was being reset on each request.</p>
  
  <p>This is being supplied to a set of repository services that handle converting the data from each endpoint into objects used within the system. Consumers use the appropriate repository to request the data needed to complete their process.</p>
  
  <p>If the amount of tokens is being reset by the bootstrap function being in service constructor, where should it be moved to within the Symfony framework that would still work with consumers?</p>