Task Queue
Pluggable task queue supporting Trigger.dev and BullMQ — auto-detected via environment variables.
Bunship's AI generation pipeline uses a pluggable task queue with two backends. The system auto-detects which backend to use based on the environment variables you provide.
Backend Comparison
| Trigger.dev | BullMQ | |
|---|---|---|
| Tasks run on | Their cloud | Your server |
| Vercel Hobby (10s) | ✅ Works | ❌ No persistent process |
| Vercel Pro (300s) | ✅ Works | ❌ No persistent process |
| Self-hosted (VPS) | ✅ Works | ✅ Works |
| Requires Redis | No | Yes |
| Stale recovery | Scheduled task (cloud) | setInterval |
Auto-Detection
The adapter is selected by the first matching environment variable:
TRIGGER_SECRET_KEY -> Trigger.dev (highest priority)
(fallback) -> BullMQNo code changes needed. Set the right env var for your deployment.
Option A: Trigger.dev (Recommended for Vercel)
Best for Vercel deployments. Tasks run on Trigger.dev's cloud infrastructure.
Setup
- Create account at cloud.trigger.dev
- Create a project, note your Project ID and Secret Key
- Install the SDK:
bun add @trigger.dev/sdk- Add environment variables:
TRIGGER_SECRET_KEY=sk_dev_your_key_here
TRIGGER_PROJECT_ID=your_project_idLocal Development
# Terminal 1: Start Trigger.dev local dev worker
cd apps/ship-api
npx trigger.dev@latest dev
# Terminal 2: Start your app
bun run devDeploy Tasks
Manual deploy:
cd apps/ship-api
npx trigger.dev@latest deployThis registers ai-generate and the ai-stale-recovery schedule on Trigger.dev.
If your local shell has OTEL_* environment variables (e.g. from Shelltime or other monitoring tools), deploy will fail with cannot merge resource due to conflicting Schema URL. Either clear these variables before deploying or use the CI workflow below.
CI/CD Deploy (GitHub Actions)
A workflow at .github/workflows/deploy-trigger.yml automatically deploys tasks when you push changes to main.
Triggers:
- Push to
mainthat modifiesapps/ship-api/src/services/ai/queue/**ortrigger.config.ts - Manual dispatch from the Actions tab
Required GitHub Secrets:
| Secret | Description |
|---|---|
TRIGGER_ACCESS_TOKEN | Personal Access Token (tr_pat_ prefix). Generate at cloud.trigger.dev/account/tokens |
TRIGGER_PROJECT_ID | Your Trigger.dev project ref (e.g. proj_xxx). Optional for the main repo if the default in trigger.config.ts is correct |
For forked repos: Fork users set their own TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID in their repo's Settings → Secrets. The workflow deploys to their own Trigger.dev project — no conflict with the upstream repo.
Production Env Vars (Trigger.dev)
After deployment, tasks run on Trigger.dev cloud. Configure these in Trigger.dev project Environment Variables for prod:
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | Yes | Read/write task, billing, and recovery data |
TRIGGER_SECRET_KEY | Yes | Trigger adapter and SDK auth |
S3_ENDPOINT | Yes | Object storage endpoint |
S3_REGION | Yes | Object storage region |
S3_ACCESS_KEY | Yes | Object storage key |
S3_SECRET_KEY | Yes | Object storage secret |
S3_BUCKET | Yes | Output bucket |
NEXT_PUBLIC_S3_URL_BASE | Yes | Public output URL base |
TRIGGER_PROJECT_ID | Optional | Project routing (config has fallback) |
Provider-specific vars (only for enabled providers):
| Variable | Needed when |
|---|---|
FAL_API_KEY | Using fal provider |
REPLICATE_API_TOKEN | Using replicate provider |
KIE_API_KEY | Using kie provider |
KIE_API_BASE_URL | Optional override for kie API base URL |
Optional tuning vars:
| Variable | Default | Purpose |
|---|---|---|
AI_STALE_QUEUE_FAILOVER_MS | 900000 | Base stale timeout |
AI_STALE_QUEUE_FAILOVER_GRACE_MS | 120000 | Extra grace after queue timeout |
AI_STALE_QUEUE_SCAN_LIMIT | 50 | Recovery scan batch size |
Option B: BullMQ
Best for self-hosted deployments with a persistent server (Railway, Fly.io, VPS).
Requirements
- Redis instance (Upstash, Railway Redis, or self-hosted)
- Persistent process (not serverless)
Setup
- Ensure
REDIS_URLis set and noTRIGGER_SECRET_KEYis present:
REDIS_URL=redis://your-redis-url:6379- Deploy
ship-apias a standalone server:
cd apps/ship-api
bun run src/index.tsThe BullMQ worker starts automatically with admission control, retries, and stale-task scanning.
Stale Task Recovery
Regardless of backend, Bunship includes a safety net that automatically fails stuck tasks and refunds credits.
| Backend | Recovery Mechanism |
|---|---|
| Trigger.dev | ai-stale-recovery scheduled task (every 5 min, cloud) |
| BullMQ | setInterval in persistent worker process |
Code Map
apps/ship-api/src/services/ai/queue/
├── types.ts # TaskQueueAdapter interface
├── processor.ts # Shared execution logic
├── adapter-bullmq.ts # BullMQ implementation
├── adapter-trigger.ts # Trigger.dev implementation
└── index.ts # Auto-detection + adapter export