# Attune Worker Containers

This directory contains Docker configurations for building Attune worker containers with different runtime capabilities.

## Overview

Attune workers can run in containers with specialized runtime environments. Workers automatically declare their capabilities when they register with the system, enabling intelligent action scheduling based on runtime requirements.

## Worker Variants

### Base Worker (`worker-base`)
- **Runtimes**: `shell`
- **Base Image**: Debian Bookworm Slim
- **Size**: ~580 MB
- **Use Case**: Lightweight workers for shell scripts and basic automation
- **Build**: `make docker-build-worker-base`

### Python Worker (`worker-python`)
- **Runtimes**: `shell`, `python`
- **Base Image**: Python 3.11 Slim
- **Size**: ~1.2 GB
- **Includes**: pip, virtualenv, common Python libraries (requests, pyyaml, jinja2, python-dateutil)
- **Use Case**: Python actions and scripts with dependencies
- **Build**: `make docker-build-worker-python`

### Node.js Worker (`worker-node`)
- **Runtimes**: `shell`, `node`
- **Base Image**: Node 20 Slim
- **Size**: ~760 MB
- **Includes**: npm, yarn
- **Use Case**: JavaScript/TypeScript actions and npm packages
- **Build**: `make docker-build-worker-node`

### Full Worker (`worker-full`)
- **Runtimes**: `shell`, `python`, `node`, `native`
- **Base Image**: Debian Bookworm
- **Size**: ~1.6 GB
- **Includes**: Python 3.x, Node.js 20, build tools
- **Use Case**: General-purpose automation requiring multiple runtimes
- **Build**: `make docker-build-worker-full`

## Building Worker Images

### Build All Variants
```bash
make docker-build-workers
```

### Build Individual Variants
```bash
# Base worker (shell only)
make docker-build-worker-base

# Python worker
make docker-build-worker-python

# Node.js worker
make docker-build-worker-node

# Full worker (all runtimes)
make docker-build-worker-full
```

### Direct Docker Build
```bash
# Using Docker directly with BuildKit
DOCKER_BUILDKIT=1 docker build \
  --target worker-python \
  -t attune-worker:python \
  -f docker/Dockerfile.worker \
  .
```

## Running Workers

### Using Docker Compose
```bash
# Start specific worker type
docker-compose up -d worker-python

# Start all workers
docker-compose up -d worker-shell worker-python worker-node worker-full

# Scale workers
docker-compose up -d --scale worker-python=3
```

### Using Docker Run
```bash
docker run -d \
  --name worker-python-01 \
  --network attune_attune-network \
  -e ATTUNE_WORKER_NAME=worker-python-01 \
  -e ATTUNE_WORKER_RUNTIMES=shell,python \
  -e ATTUNE__DATABASE__URL=postgresql://attune:attune@postgres:5432/attune \
  -e ATTUNE__MESSAGE_QUEUE__URL=amqp://attune:attune@rabbitmq:5672 \
  -v $(pwd)/packs:/opt/attune/packs:ro \
  attune-worker:python
```

## Runtime Capability Declaration

Workers declare their capabilities in three ways (in order of precedence):

### 1. Environment Variable (Highest Priority)
```bash
ATTUNE_WORKER_RUNTIMES="shell,python,custom"
```

### 2. Configuration File
```yaml
worker:
  capabilities:
    runtimes: ["shell", "python"]
```

### 3. Auto-Detection (Fallback)
Workers automatically detect available runtimes by checking for binaries:
- `python3` or `python` → adds `python`
- `node` → adds `node`
- Always includes `shell` and `native`

## Configuration

### Key Environment Variables

| Variable | Description | Example |
|----------|-------------|---------|
| `ATTUNE_WORKER_NAME` | Unique worker identifier | `worker-python-01` |
| `ATTUNE_WORKER_RUNTIMES` | Comma-separated runtime list | `shell,python` |
| `ATTUNE_WORKER_TYPE` | Worker type | `container` |
| `ATTUNE__DATABASE__URL` | PostgreSQL connection | `postgresql://...` |
| `ATTUNE__MESSAGE_QUEUE__URL` | RabbitMQ connection | `amqp://...` |
| `RUST_LOG` | Log level | `info`, `debug`, `trace` |

### Resource Limits

Set CPU and memory limits in `docker-compose.override.yml`:

```yaml
services:
  worker-python:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M
```

## Custom Worker Images

### Extend Python Worker

Create a custom worker with additional packages:

```dockerfile
# Dockerfile.worker.ml
FROM attune-worker:python

USER root

# Install ML packages
RUN pip install --no-cache-dir \
    pandas \
    numpy \
    scikit-learn \
    torch

USER attune

ENV ATTUNE_WORKER_RUNTIMES="shell,python,ml"
```

Build and run:
```bash
docker build -t attune-worker:ml -f Dockerfile.worker.ml .
docker run -d --name worker-ml-01 ... attune-worker:ml
```

### Add New Runtime

Example: Adding Ruby support

```dockerfile
FROM attune-worker:base

USER root

RUN apt-get update && apt-get install -y \
    ruby-full \
    && rm -rf /var/lib/apt/lists/*

USER attune

ENV ATTUNE_WORKER_RUNTIMES="shell,ruby"
```

## Architecture

### Multi-stage Build

The `Dockerfile.worker` uses a multi-stage build pattern:

1. **Builder Stage**: Compiles the Rust worker binary
   - Uses BuildKit cache mounts for fast incremental builds
   - Shared across all worker variants

2. **Runtime Stages**: Creates specialized worker images
   - `worker-base`: Minimal shell runtime
   - `worker-python`: Python runtime
   - `worker-node`: Node.js runtime
   - `worker-full`: All runtimes

### Build Cache

BuildKit cache mounts dramatically speed up builds:
- First build: ~5-6 minutes
- Incremental builds: ~30-60 seconds

Cache is shared across builds using `sharing=locked` to prevent race conditions.

## Security

### Non-root Execution
All workers run as user `attune` (UID 1000)

### Read-only Packs
Pack files are mounted read-only to prevent modification:
```yaml
volumes:
  - ./packs:/opt/attune/packs:ro  # :ro = read-only
```

### Network Isolation
Workers run in isolated Docker network with only necessary service access

### Secret Management
Use environment variables for sensitive data; never hardcode in images

## Monitoring

### Check Worker Registration
```bash
docker-compose exec postgres psql -U attune -d attune -c \
  "SELECT name, worker_type, status, capabilities->>'runtimes' as runtimes FROM worker;"
```

### View Logs
```bash
docker-compose logs -f worker-python
```

### Check Resource Usage
```bash
docker stats attune-worker-python
```

### Verify Health
```bash
docker-compose ps | grep worker
```

## Troubleshooting

### Worker Not Registering

**Check database connectivity:**
```bash
docker-compose logs worker-python | grep -i database
```

**Verify environment:**
```bash
docker-compose exec worker-python env | grep ATTUNE
```

### Runtime Not Detected

**Check runtime availability:**
```bash
docker-compose exec worker-python python3 --version
docker-compose exec worker-python node --version
```

**Force runtime declaration:**
```bash
ATTUNE_WORKER_RUNTIMES=shell,python
```

### Actions Not Scheduled

**Verify runtime match:**
```sql
-- Check action runtime requirement
SELECT a.ref, r.name as runtime 
FROM action a 
JOIN runtime r ON a.runtime = r.id 
WHERE a.ref = 'core.my_action';

-- Check worker capabilities
SELECT name, capabilities->>'runtimes' 
FROM worker 
WHERE status = 'active';
```

## Performance

### Image Sizes

| Image | Size | Build Time (Cold) | Build Time (Cached) |
|-------|------|-------------------|---------------------|
| worker-base | ~580 MB | ~5 min | ~30 sec |
| worker-python | ~1.2 GB | ~6 min | ~45 sec |
| worker-node | ~760 MB | ~6 min | ~45 sec |
| worker-full | ~1.6 GB | ~7 min | ~60 sec |

### Optimization Tips

1. **Use specific variants**: Don't use `worker-full` if you only need Python
2. **Enable BuildKit**: Dramatically speeds up builds
3. **Layer caching**: Order Dockerfile commands from least to most frequently changed
4. **Multi-stage builds**: Keeps runtime images small

## Files

- `Dockerfile.worker` - Multi-stage worker Dockerfile with all variants
- `README.worker.md` - This file
- `../docker-compose.yaml` - Service definitions for all workers

## References

- [Worker Containerization Design](../docs/worker-containerization.md)
- [Quick Start Guide](../docs/worker-containers-quickstart.md)
- [Worker Service Architecture](../docs/architecture/worker-service.md)
- [Production Deployment](../docs/production-deployment.md)

## Quick Commands

```bash
# Build all workers
make docker-build-workers

# Start all workers
docker-compose up -d worker-shell worker-python worker-node worker-full

# Check worker status
docker-compose exec postgres psql -U attune -d attune -c \
  "SELECT name, status, capabilities FROM worker;"

# View Python worker logs
docker-compose logs -f worker-python

# Restart worker
docker-compose restart worker-python

# Scale Python workers
docker-compose up -d --scale worker-python=3

# Stop all workers
docker-compose stop worker-shell worker-python worker-node worker-full
```
