# `PhoenixKit.ScheduledJobs`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v1.7.165/lib/phoenix_kit/scheduled_jobs.ex#L1)

Context module for managing scheduled jobs.

Provides functions to create, cancel, and process scheduled jobs. The system uses
a behaviour-based handler pattern for extensibility - any module implementing
`PhoenixKit.ScheduledJobs.Handler` can be used to handle scheduled tasks.

## Usage

    # Schedule a job using a handler module
    {:ok, job} = ScheduledJobs.schedule_job(
      MyApp.Posts.ScheduledPostHandler,
      post.uuid,
      ~U[2025-01-15 10:00:00Z],
      %{notify: true}
    )

    # Cancel a scheduled job
    {:ok, job} = ScheduledJobs.cancel_job(job)

    # Process all pending jobs (called by cron worker)
    {:ok, %{executed: 5, failed: 1}} = ScheduledJobs.process_pending_jobs()

## Handler Pattern

Handlers must implement the `PhoenixKit.ScheduledJobs.Handler` behaviour:

    defmodule MyHandler do
      @behaviour PhoenixKit.ScheduledJobs.Handler

      def job_type, do: "my_job"
      def resource_type, do: "my_resource"
      def execute(resource_uuid, args), do: :ok
    end

# `cancel_job`

Cancels a scheduled job.

Only pending jobs can be cancelled. Returns error if job is already executed or cancelled.

## Examples

    iex> cancel_job(job)
    {:ok, %ScheduledJob{status: "cancelled"}}

    iex> cancel_job(already_executed_job)
    {:error, :already_executed}

# `cancel_jobs_for_resource`

Cancels all pending jobs for a specific resource.

Useful when deleting a resource or when rescheduling.

## Examples

    iex> cancel_jobs_for_resource("post", post.uuid)
    {3, nil}

# `delete_old_jobs`

Deletes old completed jobs to prevent table bloat.

## Parameters

- `days` - Retention period in days (default: 7)
- `statuses` - List of statuses to delete (default: ["executed", "failed", "cancelled"])

## Returns

- `{count, nil}` - Number of deleted records

## Examples

    iex> delete_old_jobs(7)
    {1234, nil}

    iex> delete_old_jobs(30, ["executed"])
    {500, nil}

# `get_job`

Gets a scheduled job by ID.

# `get_jobs_for_resource`

Gets all scheduled jobs for a resource.

## Examples

    iex> get_jobs_for_resource("post", post.uuid)
    [%ScheduledJob{}, ...]

# `get_pending_job_for_resource`

Gets the pending job for a resource (if any).

## Examples

    iex> get_pending_job_for_resource("post", post.uuid)
    %ScheduledJob{status: "pending"}

# `get_pending_jobs`

Gets all pending jobs that are due for execution.

## Parameters

- `as_of` - DateTime to check against (default: now)

## Examples

    iex> get_pending_jobs()
    [%ScheduledJob{}, ...]

# `process_pending_jobs`

Processes all pending jobs that are due for execution.

Called by the cron worker every minute. Jobs are processed in priority order
(highest first), then by scheduled_at (oldest first).

## Returns

- `{:ok, %{executed: count, failed: count}}` - Processing summary

## Examples

    iex> process_pending_jobs()
    {:ok, %{executed: 5, failed: 1}}

# `reschedule_job`

Reschedules a job to a new time.

Resets attempts and clears any previous errors.

## Examples

    iex> reschedule_job(job, ~U[2025-01-20 10:00:00Z])
    {:ok, %ScheduledJob{}}

# `schedule_job`

Schedules a new job.

## Parameters

- `handler_module` - Module implementing `PhoenixKit.ScheduledJobs.Handler`
- `resource_uuid` - UUID of the target resource
- `scheduled_at` - DateTime when the job should execute
- `args` - Optional map of additional arguments (default: %{})
- `opts` - Optional keyword list with:
  - `:priority` - Job priority (default: 0)
  - `:max_attempts` - Max retry attempts (default: 3)
  - `:created_by_uuid` - UUID of user creating the job

## Returns

- `{:ok, %ScheduledJob{}}` - Job created successfully
- `{:error, changeset}` - Validation failed

## Examples

    iex> schedule_job(PostHandler, post.uuid, ~U[2025-01-15 10:00:00Z])
    {:ok, %ScheduledJob{}}

    iex> schedule_job(EmailHandler, email.uuid, scheduled_at, %{template: "welcome"}, priority: 10)
    {:ok, %ScheduledJob{}}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
