Repeating Work

The basic form of a repeating function in Fritter has a signature that looks like this:

def work(steps: StepsT, scheduled: SomeScheduledCall) -> None: ...

The parameters are, respectively, the steps that work should perform in this invocation, and an object with a .cancel() method that will stop the next iteration from occurring.

Sometimes, real time moves more quickly than your code can keep up. Perhaps your code is slow, or you need to wait on an external system; whatever the reason, if if you’ve got a timer that is supposed to repeat every N seconds, eventually, you’ll see a repetition happen after 2N seconds, or more. At that point, any logic needs to catch up.

steps can reflect this multiple ways, depending on the type of recurrence you are using. Recurrence rules

And of course you need to be able to stop the repetition, and the stopper’s .cancel() method is there to help you do that.

Let’s get set up with our imports.

from fritter.boundaries import SomeScheduledCall
from fritter.drivers.sleep import SleepDriver
from fritter.repeat import repeatedly
from fritter.repeat.rules.seconds import EverySecond
from fritter.scheduler import schedulerFromDriver

To demonstrate some repetitions, let’s set up a SleepDriver. The sleep driver will run stuff in real time with no event loop; just blocking while work is still scheduled with the driver.

driver = SleepDriver()
start = driver.now()


Let’s define some repeating work that runs for a finite number of times; it should stop after 2 seconds, by cancelling its stopper:

def work(steps: int, scheduled: SomeScheduledCall) -> None:
    elapsed = driver.now() - start
    print(f"took {steps} steps at {elapsed:0.2f}")
    if elapsed >= 2.0:
        scheduled.cancel()


Next, we’ll use repeatedly with a scheduler wrapped around our driver, and then block the driver:

repeatedly(schedulerFromDriver(driver), work, EverySecond(0.05))
steps = driver.block()
print(f"took {steps } steps, then stopped")

This will print out a bunch of steps, taking 2 wall-clock seconds to run, and the output should look something like this:

took 1 steps at 0.00
took 1 steps at 0.05
took 1 steps at 0.11
 ...
took 1 steps at 1.95
took 1 steps at 2.01
took 40 steps, then stopped
from asyncio import run

from fritter.boundaries import (
    Cancellable,
    PhysicalScheduler,
)
from fritter.drivers.asyncio import AsyncioAsyncDriver, AsyncioTimeDriver
from fritter.repeat import Async
from fritter.repeat.rules.seconds import EverySecond
from fritter.scheduler import schedulerFromDriver


from asyncio import run

from fritter.boundaries import (
    Cancellable,
    PhysicalScheduler,
)
from fritter.drivers.asyncio import AsyncioAsyncDriver, AsyncioTimeDriver
from fritter.repeat import Async
from fritter.repeat.rules.seconds import EverySecond
from fritter.scheduler import schedulerFromDriver