Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>A Token Bucket is fairly simple to implement.</p> <p>Start with a bucket with 5 tokens.</p> <p>Every 5/8 seconds: If the bucket has less than 5 tokens, add one.</p> <p>Each time you want to send a message: If the bucket has ≥1 token, take one token out and send the message. Otherwise, wait/drop the message/whatever.</p> <p>(obviously, in actual code, you'd use an integer counter instead of real tokens and you can optimize out the every 5/8s step by storing timestamps)</p> <hr> <p>Reading the question again, if the rate limit is fully reset each 8 seconds, then here is a modification:</p> <p>Start with a timestamp, <code>last_send</code>, at a time long ago (e.g., at the epoch). Also, start with the same 5-token bucket.</p> <p>Strike the every 5/8 seconds rule.</p> <p>Each time you send a message: First, check if <code>last_send</code> ≥ 8 seconds ago. If so, fill the bucket (set it to 5 tokens). Second, if there are tokens in the bucket, send the message (otherwise, drop/wait/etc.). Third, set <code>last_send</code> to now.</p> <p>That should work for that scenario.</p> <hr> <p>I've actually written an IRC bot using a strategy like this (the first approach). Its in Perl, not Python, but here is some code to illustrate:</p> <p>The first part here handles adding tokens to the bucket. You can see the optimization of adding tokens based on time (2nd to last line) and then the last line clamps bucket contents to the maximum (MESSAGE_BURST)</p> <pre class="lang-perl prettyprint-override"><code> my $start_time = time; ... # Bucket handling my $bucket = $conn-&gt;{fujiko_limit_bucket}; my $lasttx = $conn-&gt;{fujiko_limit_lasttx}; $bucket += ($start_time-$lasttx)/MESSAGE_INTERVAL; ($bucket &lt;= MESSAGE_BURST) or $bucket = MESSAGE_BURST; </code></pre> <p>$conn is a data structure which is passed around. This is inside a method that runs routinely (it calculates when the next time it'll have something to do, and sleeps either that long or until it gets network traffic). The next part of the method handles sending. It is rather complicated, because messages have priorities associated with them.</p> <pre class="lang-perl prettyprint-override"><code> # Queue handling. Start with the ultimate queue. my $queues = $conn-&gt;{fujiko_queues}; foreach my $entry (@{$queues-&gt;[PRIORITY_ULTIMATE]}) { # Ultimate is special. We run ultimate no matter what. Even if # it sends the bucket negative. --$bucket; $entry-&gt;{code}(@{$entry-&gt;{args}}); } $queues-&gt;[PRIORITY_ULTIMATE] = []; </code></pre> <p>That's the first queue, which is run no matter what. Even if it gets our connection killed for flooding. Used for extremely important things, like responding to the server's PING. Next, the rest of the queues:</p> <pre class="lang-perl prettyprint-override"><code> # Continue to the other queues, in order of priority. QRUN: for (my $pri = PRIORITY_HIGH; $pri &gt;= PRIORITY_JUNK; --$pri) { my $queue = $queues-&gt;[$pri]; while (scalar(@$queue)) { if ($bucket &lt; 1) { # continue later. $need_more_time = 1; last QRUN; } else { --$bucket; my $entry = shift @$queue; $entry-&gt;{code}(@{$entry-&gt;{args}}); } } } </code></pre> <p>Finally, the bucket status is saved back to the $conn data structure (actually a bit later in the method; it first calculates how soon it'll have more work)</p> <pre class="lang-perl prettyprint-override"><code> # Save status. $conn-&gt;{fujiko_limit_bucket} = $bucket; $conn-&gt;{fujiko_limit_lasttx} = $start_time; </code></pre> <p>As you can see, the actual bucket handling code is very small — about four lines. The rest of the code is priority queue handling. The bot has priority queues so that e.g., someone chatting with it can't prevent it from doing its important kick/ban duties.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload