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

# CPLN Task Runner

> Deploy CPLN Task Runner on Control Plane using the Template Catalog. Covers configuration, scaling, and HTTP-based task queuing with retry, scheduling, and rate limiting.

## Overview

Control Plane Task Runner is a self-hosted task queue and scheduler service similar to Google Cloud Tasks. It provides HTTP-based task enqueuing with automatic retry, delayed and scheduled execution, per-client rate limiting, and multi-queue support with priority levels.

### What Gets Created

* **API Workload** — HTTP endpoint for enqueuing tasks, managing clients, and health checks. Scales between 1 and 3 replicas by default.
* **Worker Workload** — Background processor that picks tasks off the queue and executes them. Scales between 1 and 5 replicas by default.
* **Redis with Sentinel** — A Redis instance with Redis Sentinel for high-availability task persistence and coordination. Sentinel monitors the Redis primary and handles automatic failover.
* **Secret** — An opaque secret containing Redis and Sentinel passwords and the admin API key (when `createSecret` is `true`).
* **Identity & Policy** — An identity bound to the workloads with `reveal` access to the task runner secrets.

### Architecture

The API workload receives task submissions over HTTP and pushes them into Redis. The Worker workload polls Redis and executes tasks by making outbound HTTP requests to the configured target URLs. Both workloads connect to Redis via Sentinel for failover resilience.

<Note>
  This template does not create a GVC. You must deploy it into an existing GVC.
</Note>

## Installation

This template has no external prerequisites. To install, follow the instructions for your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
# Same image for both API and Worker workloads
image: controlplanecorporation/cpln-task-runner:0.4

# API configuration
api:
  enabled: true
  replicas:
    min: 1
    max: 3
  port: 8080
  public:
    enabled: true
    pathPrefix: "" # Path prefix for public endpoint (empty for root)
  resources:
    cpu: 500m
    memory: 512Mi
  env:
    logLevel: info # debug, info, warn, error
    adminApiKey: "" # Admin API key for protected endpoints (leave empty to disable)
    otelEndpoint: "" # OpenTelemetry endpoint (leave empty to disable tracing)
    connectRetries: 30
    retryIntervalSec: 2

# Worker configuration
worker:
  enabled: true
  replicas:
    min: 1
    max: 5
  port: 8082 # Used for health checks
  resources:
    cpu: 1
    memory: 1Gi
  env:
    logLevel: info
    concurrency: 10 # Concurrent workers per replica
    taskTimeoutSec: 1800 # Task timeout (default: 30 minutes)
    maxRetry: 5 # Maximum retry attempts
    allowPrivateUrls: false # Allow tasks to target private/internal URLs
    cbFailureThreshold: 5 # Circuit breaker failure threshold
    cbTimeoutSec: 30 # Circuit breaker timeout in seconds
    connectRetries: 30
    retryIntervalSec: 2
    otelEndpoint: ""

# Creates a secret for Redis + Sentinel passwords and admin API key
createSecret: true
secretName: task-runner-secrets # Must match names below if createSecret is true

# Redis configuration
redis:
  redisPassword: mypassword # Change before deploying to production
  sentinelPassword: mypassword # Change before deploying to production
  admin:
    fromSecret:
      name: task-runner-secrets
      apiKeyKey: admin-api-key
  redis:
    auth:
      fromSecret:
        enabled: true
        name: task-runner-secrets
        passwordKey: redis-password
    persistence:
      enabled: true
  sentinel:
    auth:
      fromSecret:
        enabled: true
        name: task-runner-secrets
        passwordKey: redis-sentinel-password
    persistence:
      enabled: true
```

### API Workload

* `api.enabled` — Enable or disable the API workload.
* `api.replicas` — Min/max replica count for autoscaling (default: 1–3).
* `api.port` — Container port (default `8080`).
* `api.public.enabled` — Expose the API to the public internet.
* `api.public.pathPrefix` — Optional path prefix for the public endpoint. Leave empty to serve from the root.
* `api.resources` — CPU and memory allocated to each API replica.
* `api.env.logLevel` — Log verbosity: `debug`, `info`, `warn`, or `error`.
* `api.env.adminApiKey` — API key for admin-protected endpoints. Leave empty to disable admin authentication.
* `api.env.connectRetries` / `api.env.retryIntervalSec` — Redis connection retry behavior on startup.

### Worker Workload

* `worker.enabled` — Enable or disable the Worker workload.
* `worker.replicas` — Min/max replica count for autoscaling (default: 1–5).
* `worker.resources` — CPU and memory allocated to each Worker replica.
* `worker.env.concurrency` — Number of tasks a single Worker replica can execute concurrently.
* `worker.env.taskTimeoutSec` — Maximum duration in seconds before a task execution is considered failed (default `1800`).
* `worker.env.maxRetry` — Maximum number of retry attempts for a failed task.
* `worker.env.allowPrivateUrls` — When `true`, allows tasks to target internal/private URLs.
* `worker.env.cbFailureThreshold` / `worker.env.cbTimeoutSec` — Circuit breaker settings to stop hammering failing endpoints.

### Secrets and Redis

When `createSecret` is `true`, the template automatically creates a secret named by `secretName` containing the Redis password, Sentinel password, and admin API key. The `redis.*.fromSecret` fields are pre-wired to reference this secret.

When using an existing secret (`createSecret: false`), update the `redis.*.fromSecret` fields to point to your secret name and the correct keys.

<Note>
  Change the default `redis.redisPassword` and `redis.sentinelPassword` values before deploying to production.
</Note>

### Enqueuing Tasks

Once deployed, submit tasks to the API workload's public endpoint:

```bash theme={null}
curl -X POST https://your-api-endpoint/v1/enqueue \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "my-service",
    "queue": "default",
    "task": {
      "url": "https://api.example.com/webhook",
      "method": "POST",
      "headers": {"Content-Type": "application/json"},
      "body": "{\"event\": \"user.created\"}"
    }
  }'
```

### Admin Endpoints

When `api.env.adminApiKey` is set, admin endpoints require the `X-Admin-Key` header:

```bash theme={null}
# List clients
curl https://your-api-endpoint/admin/clients \
  -H "X-Admin-Key: your-admin-key"

# Create or update a client
curl -X POST https://your-api-endpoint/admin/clients/set \
  -H "X-Admin-Key: your-admin-key" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "new-service",
    "tier": "premium",
    "enabled": true
  }'
```

### Rate Limiting

Rate limits are applied per client and configured via the admin API. Available tiers:

| Tier         | Requests/min | Max Concurrent |
| ------------ | ------------ | -------------- |
| `free`       | 10           | 1              |
| `basic`      | 100          | 5              |
| `premium`    | 1,000        | 20             |
| `enterprise` | 5,000        | 50             |

### OpenTelemetry

To enable distributed tracing, set `otelEndpoint` in both `api.env` and `worker.env`. In your GVC configuration, ensure the **Tracing Provider** is set to **Control Plane**, then use the default HTTP collector endpoint:

```text theme={null}
tracing.controlplane:4318
```

## External References

<CardGroup cols={2}>
  <Card title="OpenTelemetry Documentation" icon="chart-line" href="https://opentelemetry.io/docs/">
    OpenTelemetry distributed tracing documentation
  </Card>

  <Card title="CPLN Task Runner Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/cpln-task-runner">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
