| name | pikku-queue |
| description | Use when adding background job processing, async task queues, or distributed workers to a Pikku app. Covers wireQueueWorker, job enqueuing, progress tracking, retries, BullMQ and PgBoss adapters. TRIGGER when: code uses wireQueueWorker, user asks about background jobs, task queues, async processing, BullMQ, PgBoss, or job retries. DO NOT TRIGGER when: user asks about scheduled cron tasks (use pikku-cron) or event-driven triggers (use pikku-trigger). |
| installGroups | ["core"] |
Pikku Queue Wiring
Agent Operating Procedure
Use this skill as an execution checklist, not reference material.
- Discover before editing. Prefer OpenCode tools such as
pikku-meta when available; otherwise run the relevant pikku meta ... --json command and inspect only the focused output you need.
- Identify the source files that own the behavior. Do not start by reading generated output,
.pikku, node_modules, vendored packages, or broad build artifacts.
- Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
- Validate with the narrowest relevant command first, then run
pikku-verify or pikku all when functions, wirings, schemas, or generated clients may have changed.
- If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
Wire Pikku functions as background queue workers. Supports job control (progress, retry, discard), configurable concurrency, and type-safe job publishing.
Before You Start
pikku info functions --verbose
pikku info tags --verbose
See pikku-concepts for the core mental model.
API Reference
wireQueueWorker(config)
import { wireQueueWorker } from '@pikku/core/queue'
wireQueueWorker({
name: string,
func: PikkuFunc,
config?: {
batchSize?: number,
removeOnComplete?: number | boolean,
},
})
Wire Object (wire.queue)
Inside queue worker functions:
wire.queue.updateProgress(percent: number)
wire.queue.discard(reason: string)
wire.queue.fail(reason: string)
Job Publishing
const jobId = await queue.add(queueName, data, options?)
Options:
{
priority?: number,
delay?: number,
attempts?: number,
backoff?: {
type: 'exponential' | 'fixed',
delay: number,
},
}
Usage Patterns
Basic Queue Worker
const processReminder = pikkuSessionlessFunc({
title: 'Process Reminder',
func: async ({ db, emailService }, { todoId, userId }) => {
const todo = await db.getTodo(todoId)
await emailService.sendReminder(userId, todo)
return { sent: true }
},
})
wireQueueWorker({
name: 'todo-reminders',
func: processReminder,
})
Job Control (Progress, Discard, Fail)
const processReminder = pikkuSessionlessFunc({
title: 'Process Reminder',
func: async ({ db }, { todoId }, wire) => {
await wire.queue.updateProgress(25)
const todo = await db.getTodo(todoId)
if (!todo) {
await wire.queue.discard('Todo not found')
return
}
if (todo.completed) {
await wire.queue.fail('Todo already completed')
return
}
await wire.queue.updateProgress(100)
return { sent: true }
},
})
Retries & Configuration
wireQueueWorker({
name: 'todo-reminders',
func: processReminder,
config: {
batchSize: 5,
removeOnComplete: 100,
},
})
const jobId = await queue.add(
'todo-reminders',
{
todoId: 'abc-123',
userId: 'user-456',
},
{
priority: 10,
delay: 5000,
attempts: 3,
backoff: { type: 'exponential', delay: 1000 },
}
)
Type-Safe Queue Publishing
After npx pikku all:
import { PikkuQueue } from '.pikku/pikku-queue.gen.js'
const queue = new PikkuQueue(queueService)
const jobId = await queue.add('todo-reminders', {
todoId: 'abc-123',
userId: 'user-456',
})
const job = await queue.getJob('todo-reminders', jobId)
const status = await job.status()
const result = await job.waitForCompletion(30_000)
Queue Adapters
BullMQ (Redis-based):
import { BullMQQueueService } from '@pikku/queue-bullmq'
const queueService = new BullMQQueueService({
connection: { host: 'localhost', port: 6379 },
})
PgBoss (PostgreSQL-based):
import { PgBossQueueService } from '@pikku/queue-pg-boss'
const queueService = new PgBossQueueService({
connectionString: 'postgres://...',
})
Complete Example
export const sendWelcomeEmail = pikkuSessionlessFunc({
title: 'Send Welcome Email',
func: async ({ emailService, db }, { userId }, wire) => {
await wire.queue.updateProgress(10)
const user = await db.getUser(userId)
if (!user) {
await wire.queue.discard('User not found')
return
}
await wire.queue.updateProgress(50)
await emailService.send({
to: user.email,
subject: 'Welcome!',
template: 'welcome',
data: { name: user.name },
})
await wire.queue.updateProgress(100)
return { sent: true, email: user.email }
},
})
wireQueueWorker({
name: 'welcome-emails',
func: sendWelcomeEmail,
config: { removeOnComplete: 100 },
})
export const registerUser = pikkuSessionlessFunc({
title: 'Register User',
func: async ({ db, queue }, { email, name }) => {
const user = await db.createUser({ email, name })
await queue.add('welcome-emails', { userId: user.id })
return { user }
},
})