aioclock

repository·main·Indexed 42 days ago

https://github.com/manimozaffar/aioclock

An asyncio-based scheduling framework for executing periodic tasks with integrated support for dependency injection and task grouping. Version 0.3.1 features include Pydantic v2 validation, process isolation for the task dispatcher, and horizontal scaling via backend synchronization. It supports various trigger types such as Every, At, Cron, Forever, Once, OnStartUp, and OnShutDown, and allows both async and sync functions to be scheduled.

Tokens
11.1K
Snippets
36
Records
56
Agent score
53%

What's inside aioclock

  1. Overview of aioclock features

    main

    aioclock is an asyncio-based scheduling framework for periodic tasks. Key features include:

    • Async-native: 100% asynchronous, lightweight, and fast.
    • Task Grouping: Organize tasks into groups for better maintainability.
    • Extensible Triggers: Pre-defined triggers that are easy to extend.
    • Pydantic v2 Validation: Validates all triggers on startup for fast failure detection.
    • Process Isolation: By default, the task dispatcher (scheduler) runs in a different process to prevent CPU-intensive tasks from delaying scheduling.
    • Horizontal Scaling: Supports backend synchronization (e.g., via Redis) to allow scaling across multiple instances.
  2. What is AioClock and its core architecture?

    main

    AioClock is a lightweight, asynchronous task scheduling framework for Python. It uses a structured approach to manage, schedule, and execute tasks using a central orchestrator called the AioClock Application.

    Key architectural concepts include:

    • Tasks: Units of work defined by a Callable and a Trigger.
    • Triggers: Conditions that initiate execution (e.g., intervals, specific times, or cron syntax).
    • Groups: Logical collections of tasks that allow for modular code organization.
    • Task Runner: The engine that monitors triggers and executes tasks in the correct order.
    • Dependency Injection: A built-in system (powered by FastDepends) that allows for loose coupling and easy testing by enabling the overriding of callables (e.g., swapping a PostgreSQL session for a SQLite session during tests).
  3. When to choose AioClock over APScheduler

    main

    Choose AioClock if:

    • You are building an automation system with task pipelining.
    • You need complex, customized scheduling and dependency injection.

    Choose APScheduler if:

    • You need to store tasks in a database rather than in Python code. (Note: You can implement database storage in AioClock using its External APIs, as described in api/external_api.md).
  4. How to organize tasks using Groups

    main
    To write modular and scalable code, you can bundle related tasks into a Group. Groups allow you to encapsulate tasks and manage them as a single unit. These groups can then be integrated into the main AioClock application using the include_group() function. Standalone tasks that are not part of a group can be defined using the @aioclock.task decorator.
  5. When to choose AioClock over FastStream

    main

    Choose AioClock if:

    • You need complex, customized scheduling and low-level API access to your broker.

    Choose FastStream if:

    • You are building a distributed data streaming application.
    • You need auto-generated AsyncAPI documentation.
    • You want a solution that abstracts away message broker details.

    Note: AioClock and FastStream can be used together in the same environment, similar to how FastAPI is used alongside other services.

  6. How the AioClock application lifecycle works

    main

    The lifecycle of an AioClock application follows these steps:

    1. Initialization: The process begins with a call to app.serve().
    2. Task Gathering: The application gathers all registered tasks and groups.
    3. Startup: The application checks for startup tasks (managed via Lifespan) and executes them.
    4. Execution Loop: The Task Runner monitors triggers and executes tasks according to their schedules.
    5. Shutdown: When the application is signaled to stop, it executes shutdown tasks (managed via Lifespan) before gracefully exiting.
  7. When to choose AioClock over Celery

    main

    Choose AioClock if:

    • You are building an automation system with high flexibility and control over broker behavior.
    • You need dependency injection.
    • You are working on Windows.

    Choose Celery if:

    • You are running background tasks specifically for web servers.
    • You want a solution that abstracts away the complexities of message brokers.

    Integration Tip: You can implement Celery-like task queue behavior in AioClock by creating a once trigger that reads from a queue. See examples/brokers.md for implementation details.

  8. When to choose AioClock over Rocketry

    main

    Choose AioClock if:

    • You need a lightweight solution without dependencies like redbird.
    • You are using Pydantic v2.
    • You require strict type safety for triggers.
    • You need predictable time-based scheduling that logs upcoming events.

    Choose Rocketry if:

    • You have heavy, CPU-intensive task pipelining requirements.
    • You are still using Pydantic v1.
  9. When to choose AioClock over Airflow

    main

    Choose AioClock if:

    • You are building an application and need quick productivity and easy setup.
    • You want high customization.
    • You are working on Windows.

    Choose Airflow if:

    • You are building standard data engineering pipelines.
    • You require distributed execution and out-of-the-box workflow monitoring.
  10. How aioclock works: Triggers, Groups, and Dependency Injection

    main

    AioClock is an asyncio-based scheduling framework that manages periodic tasks using three core concepts:

    1. Triggers: Define when a task should run. Common triggers include Every(seconds=n), At(hour=h, minute=m, second=s, tz='...'), Once(), and Forever().
    2. Groups: Use Group() to organize tasks for better maintainability. Tasks are registered to a group using the @group.task(trigger=...) decorator.
    3. Dependency Injection: Use the Depends() function within task signatures to inject dependencies. This allows tasks to access external resources or shared logic easily.

    Tasks can be either async def or standard def (synchronous), and the framework handles both.

    from aioclock import Group, Every, Depends
    
    group = Group()
    
    def my_dependency():
        return "data"
    
    @group.task(trigger=Every(seconds=10))
    async def my_task(val: str = Depends(my_dependency)):
        print(f"Running with {val}")
  11. Core features of AioClock

    main

    AioClock is designed as a lightweight, extensible scheduling framework with several key architectural advantages:

    • Simplicity: Highly extensible due to its minimal design.
    • Trigger-based scheduling: Provides flexibility for running tasks at specific future times.
    • Dependency Injection System: Uses a system similar to FastAPI, allowing you to decouple dependencies within your scheduled tasks.
    • Declarative Syntax: Promotes a clean, declarative way to define schedules.
    • Type Safety: All triggers are type-safe, making it suitable for projects where strict typing is a priority.
  12. When to choose AioClock over Crontab

    main

    Choose AioClock if:

    • You are building a full automation system rather than running isolated scripts.
    • You need task pipelining or complex/custom scheduling.
    • You are working on Windows or are unfamiliar with Unix-Linux.
    • You need dependency injection integrated into your framework layer.

    Choose Crontab if:

    • You need the absolute lightest possible solution.
    • You only need to run independent scripts at fixed intervals.
    • You prefer not to use Python.