rdev/internal/db/migrations/010_work_queue.sql
jordan 39df51defd feat: Add multi-provider code agent interface with Claude Code and OpenCode adapters
Implements weeks 1-4 of the multi-provider architecture:

Week 1 - Foundation:
- Add domain models (AgentProvider, AgentRequest, AgentEvent, AgentResult)
- Define CodeAgent port interface with Execute, Cancel, Capabilities
- Create thread-safe provider registry with first-registered default

Week 2 - Claude Code Adapter:
- Extract kubectl exec logic into CodeAgent implementation
- Parse stream-json output format (init, message, tool_use, result)
- Support session continuation via --resume flag

Week 3 - OpenCode Adapter:
- HTTP/SSE client for opencode serve API
- Session management (create, send message, abort)
- Event streaming with documented buffer rationale

Week 4 - Quality & Polish:
- Fix race condition in OpenCode Cancel method
- Add AgentRequest.Validate() with ErrPromptRequired, ErrInvalidTimeout
- Document DefaultAvailabilityTimeout constants
- Add HTTP error context for debugging

Also includes:
- Work queue system with PostgreSQL adapter
- Credential store for infrastructure secrets
- Project templates with Woodpecker CI integration
- Comprehensive test coverage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 09:25:51 -07:00

59 lines
3.1 KiB
SQL

-- Create work_queue table for worker pool task execution
-- Unlike command_queue (project-specific claudebox commands), work_queue
-- supports generic tasks that any worker in the pool can claim and execute.
CREATE TABLE IF NOT EXISTS work_queue (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
project_id VARCHAR(255) NOT NULL,
task_type VARCHAR(50) NOT NULL, -- 'build', 'test', 'deploy', 'custom'
task_spec JSONB NOT NULL, -- Task-specific parameters
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending, running, completed, failed, cancelled
priority INT NOT NULL DEFAULT 0, -- Higher = more urgent
worker_id VARCHAR(255), -- ID of worker that claimed this task
callback_url TEXT, -- URL to POST completion notification
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
result JSONB, -- Task result (output, artifacts, etc.)
error TEXT, -- Error message if failed
retry_count INT NOT NULL DEFAULT 0, -- Number of retry attempts
max_retries INT NOT NULL DEFAULT 3 -- Maximum retry attempts
);
-- Index for atomic dequeue: find pending tasks ordered by priority and age
-- Uses partial index for efficiency (only pending tasks)
CREATE INDEX IF NOT EXISTS idx_work_queue_pending
ON work_queue(priority DESC, created_at ASC)
WHERE status = 'pending';
-- Index for worker task lookup
CREATE INDEX IF NOT EXISTS idx_work_queue_worker
ON work_queue(worker_id, status)
WHERE worker_id IS NOT NULL;
-- Index for project task history
CREATE INDEX IF NOT EXISTS idx_work_queue_project
ON work_queue(project_id, created_at DESC);
-- Index for status monitoring
CREATE INDEX IF NOT EXISTS idx_work_queue_status
ON work_queue(status);
-- Index for cleanup of old completed tasks
CREATE INDEX IF NOT EXISTS idx_work_queue_completed
ON work_queue(completed_at)
WHERE status IN ('completed', 'failed', 'cancelled');
COMMENT ON TABLE work_queue IS 'Task queue for worker pool execution (build, test, deploy tasks)';
COMMENT ON COLUMN work_queue.project_id IS 'Project this task belongs to';
COMMENT ON COLUMN work_queue.task_type IS 'Type of task: build, test, deploy, or custom';
COMMENT ON COLUMN work_queue.task_spec IS 'JSON specification with task parameters (prompt, template, git_url, etc.)';
COMMENT ON COLUMN work_queue.status IS 'Task status: pending, running, completed, failed, cancelled';
COMMENT ON COLUMN work_queue.priority IS 'Task priority (higher = more urgent, 0 = default)';
COMMENT ON COLUMN work_queue.worker_id IS 'ID of the worker that claimed this task';
COMMENT ON COLUMN work_queue.callback_url IS 'Webhook URL for completion notification';
COMMENT ON COLUMN work_queue.result IS 'JSON result from task execution (output, artifacts)';
COMMENT ON COLUMN work_queue.error IS 'Error message if task failed';
COMMENT ON COLUMN work_queue.retry_count IS 'Number of times this task has been retried';
COMMENT ON COLUMN work_queue.max_retries IS 'Maximum allowed retry attempts';