Periodic tasks

You often will have tasks that you need to execute periodically (for instance, every day or every 5 minutes) or by schedule (for instance, 5 days after today). For example, create a database backup every midnight or actualize a cache of orders every 5 minutes. Wouldn’t it be great to have an event for that? Then you can get for the periodic tasks all the benefits of event-driven actors: scalability, distribution, retries, observability, and more.

Meet walnats.Clock. It’s a worker that emits periodic events. To implement a periodic task, run the clock and subscribe to the event in any other place.

class walnats.Clock

Emit periodic events.

By default, emits “minute-passed” event every 60 seconds. Use it for running scheduled and periodic tasks.

clock = walnats.Clock()
events = walnats.Events(clock.event)
async with events as conn:
    await conn.register()
    await clock.run()

The interval can be adjusted either by setting a custom duration or by using walnats.decorators.filter_time().

clock_5m = walnats.Clock(
    event=walnats.Event('5m-passed', datetime),
    duration=5 * 60,
)

It is safe to run multiple clocks on the same Nats instance, events will not be duplicated.

event: Event[datetime] = Event(name='minute-passed', schema=<class 'datetime.datetime'>, serializer=None, description=None, limits=Limits(age=None, consumers=None, messages=None, bytes=None, message_size=None))

The event to be emitted on each tick.

meta: dict[str, str] | None = None

Headers to be included into the message, same as meta argument of walnats.types.ConnectedEvents.emit().

period: int = 60

How often (in seconds) events should be emitted. The actual delta between event can fluctuate depending on when the async task gets woke up by the scheduler and how long it takes to publish the event. If, for some reason, the event can’t be emitted before the time comes to emit the next one, it won’t be emitted.

async run(conn: walnats.types.ConnectedEvents, burst: bool = False) None

Run the clock, start emitting events in an infinite loop.

Parameters:
  • conn – connected events instance.

  • burst – if True, emit one event in the right time and exit. Useful for testing.

Tips

  1. It might be a good idea to run a separate clock on each nats cluster so that in case of network failure between clusters, events will still be coming in each of them. When the connection is restored, Nats will make sure there are no duplicates.

  2. The interval between events may be affected by CPU-bound tasks running in the same process. To avoid it, make sure to use walnats.ExecuteIn.PROCESS for all CPU-heavy actors running in the same instance as the clock.

  3. If there is just one worker that needs a very specific schedule (for instance, it must be run daily at 12:03 and any other time won’t do), prefer using walnats.decorators.filter_time. If multiple workers need the same schedule (like being run once a day, doesn’t matter when), prefer providing for them a separate Clock with a fitting duration.