> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kit-rs.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Task Scheduling

> Schedule recurring tasks with Kit Laravel-like scheduler

Kit provides a powerful task scheduling system inspired by Laravel's scheduler. Schedule tasks to run at specific intervals - every minute, hourly, daily, weekly, or using custom cron expressions.

## Generating Tasks

The fastest way to create a new scheduled task is using the Kit CLI:

```bash theme={null}
kit make:task CleanupLogs
```

This command will:

1. Create `src/tasks/cleanup_logs_task.rs` with a task stub
2. Create `src/tasks/mod.rs` if it doesn't exist
3. Create `src/schedule.rs` for registering tasks
4. Create `src/bin/schedule.rs` scheduler binary

<CodeGroup>
  ```bash Examples theme={null}
  # Creates CleanupLogsTask in src/tasks/cleanup_logs_task.rs
  kit make:task CleanupLogs

  # Creates SendRemindersTask in src/tasks/send_reminders_task.rs
  kit make:task SendReminders

  # You can also include "Task" suffix (same result)
  kit make:task BackupDatabaseTask
  ```

  ```rust Generated File theme={null}
  //! CleanupLogsTask scheduled task

  use async_trait::async_trait;
  use kit::{Task, TaskResult};

  /// CleanupLogsTask - A scheduled task
  ///
  /// Register this task in `src/schedule.rs` with the fluent API.
  pub struct CleanupLogsTask;

  impl CleanupLogsTask {
      pub fn new() -> Self {
          Self
      }
  }

  #[async_trait]
  impl Task for CleanupLogsTask {
      async fn handle(&self) -> TaskResult {
          // TODO: Implement your task logic here
          println!("Running CleanupLogsTask...");
          Ok(())
      }
  }
  ```
</CodeGroup>

## Defining Schedules

Kit supports two approaches for defining scheduled tasks:

### 1. Trait-Based Tasks (Recommended)

For complex tasks that need dependencies or reusable logic, implement the `Task` trait and configure the schedule during registration:

```rust theme={null}
// src/tasks/cleanup_logs_task.rs
use async_trait::async_trait;
use kit::{Task, TaskResult, DB};
use crate::models::Log;

pub struct CleanupLogsTask;

impl CleanupLogsTask {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait]
impl Task for CleanupLogsTask {
    async fn handle(&self) -> TaskResult {
        // Access the database just like in controllers
        let db = DB::connection();

        // Delete logs older than 30 days
        Log::query()
            .filter(Log::created_at.lt(thirty_days_ago()))
            .delete()
            .await?;

        println!("Old logs cleaned up successfully");
        Ok(())
    }
}
```

Then register with fluent scheduling API in `src/schedule.rs`:

```rust theme={null}
// src/schedule.rs
use kit::Schedule;
use crate::tasks::CleanupLogsTask;

pub fn register(schedule: &mut Schedule) {
    schedule.add(
        schedule.task(CleanupLogsTask::new())
            .daily()
            .at("03:00")
            .name("cleanup:logs")
            .description("Removes logs older than 30 days")
    );
}
```

### 2. Closure-Based Tasks

For quick, inline tasks without separate files:

```rust theme={null}
// src/schedule.rs
use kit::Schedule;

pub fn register(schedule: &mut Schedule) {
    // Simple closure task
    schedule.add(
        schedule.call(|| async {
            println!("Ping! Running every minute");
            Ok(())
        })
        .every_minute()
        .name("heartbeat")
    );

    // Configured closure task
    schedule.add(
        schedule.call(|| async {
            // Your task logic
            Ok(())
        })
        .daily()
        .at("09:00")
        .name("morning-report")
        .description("Sends daily morning report")
    );
}
```

## Registering Tasks

Register your tasks in `src/schedule.rs`:

```rust theme={null}
// src/schedule.rs
use kit::Schedule;
use crate::tasks;

pub fn register(schedule: &mut Schedule) {
    // Trait-based tasks with fluent schedule configuration
    schedule.add(
        schedule.task(tasks::CleanupLogsTask::new())
            .daily()
            .at("03:00")
            .name("cleanup:logs")
            .description("Removes logs older than 30 days")
    );

    schedule.add(
        schedule.task(tasks::SendRemindersTask::new())
            .daily()
            .at("09:00")
            .name("send:reminders")
            .description("Sends daily reminder emails")
    );

    schedule.add(
        schedule.task(tasks::BackupDatabaseTask::new())
            .weekly()
            .at("00:00")
            .name("backup:database")
            .description("Weekly database backup")
            .without_overlapping()
    );

    // Closure-based tasks
    schedule.add(
        schedule.call(|| async {
            println!("Quick task!");
            Ok(())
        })
        .hourly()
        .name("quick-task")
    );
}
```

## Schedule Frequency Options

Kit provides a fluent API for defining when tasks should run:

### Common Intervals

| Method                     | Description                        |
| -------------------------- | ---------------------------------- |
| `.every_minute()`          | Run every minute                   |
| `.every_five_minutes()`    | Run every 5 minutes                |
| `.every_ten_minutes()`     | Run every 10 minutes               |
| `.every_fifteen_minutes()` | Run every 15 minutes               |
| `.every_thirty_minutes()`  | Run every 30 minutes               |
| `.hourly()`                | Run every hour at minute 0         |
| `.hourly_at(30)`           | Run every hour at minute 30        |
| `.daily()`                 | Run daily at midnight              |
| `.daily_at("03:00")`       | Run daily at 3:00 AM               |
| `.weekly()`                | Run weekly on Sunday at midnight   |
| `.monthly()`               | Run monthly on the 1st at midnight |

### Day-Specific Schedules

```rust theme={null}
use kit::DayOfWeek;

// Run on specific days
.weekly_on(DayOfWeek::Monday)
.weekly_on(DayOfWeek::Friday)

// Shorthand day methods
.sundays()
.mondays()
.tuesdays()
.wednesdays()
.thursdays()
.fridays()
.saturdays()

// Multiple days
.days(&[DayOfWeek::Monday, DayOfWeek::Wednesday, DayOfWeek::Friday])

// Weekdays/Weekends
.weekdays()  // Monday-Friday
.weekends()  // Saturday-Sunday
```

### Time Modifiers

Chain `.at()` with any schedule to set a specific time:

```rust theme={null}
.daily().at("14:30")           // Daily at 2:30 PM
.weekly().at("09:00")          // Weekly at 9:00 AM
.mondays().at("08:00")         // Every Monday at 8:00 AM
.monthly().at("00:00")         // First of month at midnight
```

### Custom Cron Expressions

For full control, use cron syntax:

```rust theme={null}
// Standard cron format: minute hour day-of-month month day-of-week
.cron("0 */2 * * *")    // Every 2 hours
.cron("30 4 * * 1-5")   // 4:30 AM on weekdays
.cron("0 0 1,15 * *")   // 1st and 15th of each month
```

## Task Configuration

### Preventing Overlapping

Prevent a task from running if a previous instance is still executing:

```rust theme={null}
schedule.add(
    schedule.task(LongRunningTask::new())
        .daily()
        .name("long-task")
        .without_overlapping()
);
```

### Running in Background

Run tasks without waiting for completion:

```rust theme={null}
schedule.add(
    schedule.task(BackgroundTask::new())
        .hourly()
        .name("background-task")
        .run_in_background()
);
```

## Running the Scheduler

Kit provides CLI commands for running scheduled tasks:

### Run Once

Execute all due tasks once (typically called by cron every minute):

```bash theme={null}
kit schedule:run
```

### Daemon Mode

Run continuously, checking for due tasks every minute:

```bash theme={null}
kit schedule:work
```

This is ideal for development or when using a process manager like systemd.

### List Tasks

Display all registered scheduled tasks:

```bash theme={null}
kit schedule:list
```

Output:

```
Scheduled Tasks:
==========================================================================================
Name                           Schedule                       Description
------------------------------------------------------------------------------------------
cleanup:logs                   0 3 * * *                      Removes logs older than 30 days
send:reminders                 0 9 * * *                      Sends daily reminder emails
backup:database                0 0 * * 0                      Weekly database backup
==========================================================================================
Total: 3 task(s)
```

### Run Specific Task

Run a specific task by name:

```bash theme={null}
cargo run --bin schedule -- run-task cleanup:logs
```

## Production Setup

### Using Cron

Add a single cron entry to run the scheduler every minute:

```bash theme={null}
* * * * * cd /path/to/your/project && kit schedule:run >> /dev/null 2>&1
```

### Using Systemd

Create a systemd service for the scheduler daemon:

```ini theme={null}
# /etc/systemd/system/myapp-scheduler.service
[Unit]
Description=MyApp Scheduler
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/kit schedule:work
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

```bash theme={null}
sudo systemctl enable myapp-scheduler
sudo systemctl start myapp-scheduler
```

## Accessing App Context

Scheduled tasks have full access to the application context, just like controllers:

```rust theme={null}
use kit::{App, Task, TaskResult, DB};
use crate::actions::SendEmailAction;
use crate::models::User;

pub struct SendRemindersTask;

#[async_trait]
impl Task for SendRemindersTask {
    async fn handle(&self) -> TaskResult {
        // Access database
        let users = User::query()
            .filter(User::reminder_enabled.eq(true))
            .all()
            .await?;

        // Use actions via dependency injection
        let send_email: SendEmailAction = App::get().unwrap();

        for user in users {
            send_email.execute(&user.email, "Daily Reminder").await?;
        }

        Ok(())
    }
}
```

## File Organization

The recommended file structure for scheduled tasks:

```
src/
├── tasks/
│   ├── mod.rs              # Re-export all tasks
│   ├── cleanup_logs_task.rs
│   ├── send_reminders_task.rs
│   └── backup_database_task.rs
├── schedule.rs             # Register tasks
├── bin/
│   └── schedule.rs         # Scheduler binary
├── bootstrap.rs
├── routes.rs
└── main.rs
```

**src/tasks/mod.rs:**

```rust theme={null}
pub mod cleanup_logs_task;
pub mod send_reminders_task;
pub mod backup_database_task;

pub use cleanup_logs_task::CleanupLogsTask;
pub use send_reminders_task::SendRemindersTask;
pub use backup_database_task::BackupDatabaseTask;
```

## Summary

| Feature         | Usage                                                          |
| --------------- | -------------------------------------------------------------- |
| Create task     | `kit make:task TaskName`                                       |
| Trait-based     | Implement `Task` trait, configure schedule during registration |
| Closure-based   | `schedule.call(\|\| async { ... })`                            |
| Register tasks  | `schedule.add(schedule.task(...).daily().name("..."))`         |
| Run once        | `kit schedule:run`                                             |
| Run daemon      | `kit schedule:work`                                            |
| List tasks      | `kit schedule:list`                                            |
| Prevent overlap | `.without_overlapping()`                                       |
| Background      | `.run_in_background()`                                         |
