RateLimiter(3pm)

πŸ“¦
version 0.01 Β· 2 versions
  • 0.01 Β· debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking (latest)
  • 0.01 Β· ubuntu jammy
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Schedule::RateLimiter β€” the RateLimiter(3pm) page, but make it cute πŸ’–

User Contributed Perl Documentation ✨ bestie, this is the manual for Schedule::RateLimiter, and it's literally just here to stop your events from happening too fast. no cap.


🌸 NAME 🌸

Schedule::RateLimiter</purpose> β€” prevent events from happening too quickly. that's it, that's the whole job, and it's iconic for it πŸ’…


✨ SYNOPSIS ✨

okay so first you use it, then you build a lil throttle, then you let it vibe:

use Schedule::RateLimiter;

# Don't let this event happen more than 5 times in a 60 second period.
my $throttle = Schedule::RateLimiter->new ( iterations => 5,
                                    seconds    => 60 );

# Cycle forever, but not too fast.
while ( 1 ) {
    $throttle->event();
    &do_something;
}

see how it's just chillin there guarding your while ( 1 )? king behavior honestly πŸ‘‘


πŸ¦‹ DESCRIPTION πŸ¦‹

so this module gives you a way to voluntarily restrict how many times a given action can take place inside a specified time frame. it's the "hey maybe don't" module. super useful if you wrote something that periodically polls some public resource and you do NOT want to be that person who overburdens it with too many requests. we are polite in this house 🫢

now, at first you might be like "bestie just sleep for the number of seconds divided by the number of iterations in between each event, problem solved." and honestly? that would only be correct if the event took no time at all. which it does. not. πŸ™ˆ

if you happen to know exactly how much time each event is going to take, then sure, you could build an even more complicated one-liner like this:

sleep( (seconds / iterations) - single_event_time )

but this module is here for the other cases β€” the ones where the exact run-time of each event is unknown and variable. and it will try very hard to let an event happen as many times as possible without exceeding the specified bounds. maximum effort, no stress ✨

for example, say you wanna write something that checks an 'incoming' directory once a minute for files and then does something with those files if it finds any:

  • if it takes you two seconds to process those files, then you wanna wait 58 seconds before polling the directory again.
  • if it takes 30 seconds to process those files, then you only wanna wait 30 seconds.
  • and if it takes 3 minutes? then you wanna poll the directory again immediately as soon as you're done. no waiting, we're back, we're ready πŸ’…

and here's what that looks like:

my $throttle = Schedule::RateLimiter->new ( seconds => 60 );
&poll_and_process while ( $throttle->event );

πŸŽ€ METHODS πŸŽ€

πŸ’œ new()

creates and returns a brand new shiny Schedule::RateLimiter object. it's giving fresh start, main character energy 🌈

the constructor takes up to three parameters:

  • block (default: true) β€” this one accepts a true or false value and sets the default "block" behavior for all the future calls to event(). it's just way more convenient to turn blocking off for an entire object all at once instead of doing it one call at a time. lazy girlies stay winning 😌
  • iterations (default: 1) β€” this specifies the number of times an event may take place within the given time period. it must be a positive, non-zero integer. no zeroes, no negatives, we're not doing that here πŸ’€
  • seconds (required) β€” this specifies the minimum number of seconds that must transpire before we will allow (iterations + 1) events to happen. a value of 0 disables throttling entirely (go off, no limits). you may also specify fractional time periods, fancy πŸ’…

example:

my $throttle = Schedule::RateLimiter->new ( iterations => 2,
                                    seconds    => 10 );

# Event 1
$throttle->event();
# Event 2
$throttle->event();
# Event 3
$throttle->event();
# 10 seconds will have transpired since event 1 at this point.
# Event 4
$throttle->event();
# 10 seconds will have transpired since event 2 at this point.

🧚 event()

you call this one to signal the beginning of an event. it returns true or false to tell you whether it's ok to proceed with the event. under the hood it uses Time::HiRes to do its calculations and its sleeping, so the precision of this method is exactly the same as the precision of Time::HiRes on your platform. iykyk ✨

it takes one (optional) parameter:

  • block (default: true) β€” if you set this to a false value, the method does a non-blocking check to see if it's ok for the event to occur. if it's not ok, it returns a false value and assumes the event did not take place. otherwise it returns a true value and assumes the event did take place. simple as that, no cap 🫢

example:

# Stop when the code moves too fast.
while ( 1 ) {
    if ($throttle->event( block => 0 )) {
        &do_something;
    } else {
        die 'I went too fast!';
    }
}

πŸ’€ BUGS πŸ’€

this module has to keep a record of when every single iteration took place, so if you're allowing a large number of iterations to happen in the given time period, this could potentially use a lot of memory. like, a lot a lot. just so you know 😭


⚠️ KNOWN ISSUES ⚠️

if you have multiple iterations that typically happen very quickly, and you wanna limit them over a long period of time, they will "clump" together. like, they all happen at just about the same time, and then the system waits for a long period before doing the same "clump" all over again. that's just the nature of the best-fit algorithm, bestie, it's not a bug it's a lifestyle πŸ’…

anything that's done to try to separate single events with longer waits than necessary will potentially create a sub-optimal situation if an event in the future takes longer than expected. so like, careful.

if you really want all of your events to start at even time periods apart from each other, then set the number of iterations to 1 and adjust the number of seconds accordingly. that's the move πŸ‘‘


πŸ‘‘ AUTHOR πŸ‘‘

Daniel J. Wright, <wright@pair.com> β€” shoutout to the legend 🫢


🌈 SEE ALSO 🌈

  • the POE module provides a more heavyweight solution to this problem as well. if this module is a lil sprinter, POE is the whole gym πŸ‹οΈ
  • perl.

and that's the whole page, bestie!! this doc ships with <code>perl v5.36.0</code> and was dated <code>2022-11-19</code> β€” so it's a lil vintage, but it ate and left no crumbs. mwah πŸ’–βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from