BunshipBunship

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.devBullMQ
Tasks run onTheir cloudYour server
Vercel Hobby (10s)✅ Works❌ No persistent process
Vercel Pro (300s)✅ Works❌ No persistent process
Self-hosted (VPS)✅ Works✅ Works
Requires RedisNoYes
Stale recoveryScheduled task (cloud)setInterval

Auto-Detection

The adapter is selected by the first matching environment variable:

TRIGGER_SECRET_KEY  ->  Web/API runtime uses the Trigger.dev adapter (highest priority)
REDIS_URL           ->  Web/API or standalone API runtime uses BullMQ
(fallback)          ->  BullMQ

No code changes needed. Set the right env var for your deployment.

Best for Vercel deployments. Tasks run on Trigger.dev's cloud infrastructure.

Setup

  1. Create account at cloud.trigger.dev
  2. Create a project, note your Project ID and the Secret Key used by Web/API to enqueue runs
  3. Confirm the SDK and CLI versions match. The current repo pins them in apps/ship-api/package.json at 4.4.6:
@trigger.dev/sdk=4.4.6
@trigger.dev/build=4.4.6
trigger.dev CLI=4.4.6
  1. Add dispatch variables to the Web/API container runtime:
TRIGGER_SECRET_KEY=sk_dev_your_key_here
TRIGGER_PROJECT_ID=your_project_id

TRIGGER_SECRET_KEY lets the app enqueue runs on Trigger.dev. It is not a Docker build variable and it is not required in Trigger cloud task runtime.

Local Development

# Terminal 1: Start Trigger.dev local dev worker
cd apps/ship-api
bun run trigger:dev

# Terminal 2: Start your app
bun run dev

Deploy Tasks

Manual deploy:

cd apps/ship-api
bun run trigger:deploy

This 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 main that modifies Trigger task directories, apps/ship-api/package.json, trigger.config.ts, or the workflow
  • Manual dispatch from the Actions tab

Required GitHub Secrets / Variables:

SecretDescription
TRIGGER_ACCESS_TOKENPersonal Access Token (tr_pat_ prefix). Generate at cloud.trigger.dev/account/tokens
TRIGGER_PROJECT_IDYour 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.

ScenarioVariablesWhere they live
Deploy tasksTRIGGER_ACCESS_TOKEN, TRIGGER_PROJECT_IDGitHub Secrets / Variables, consumed by .github/workflows/deploy-trigger.yml
Web/API dispatchTRIGGER_SECRET_KEY, optional TRIGGER_PROJECT_IDWeb/API container runtime env
Trigger cloud task executionDATABASE_URL, S3_*, PUBLIC_S3_URL_BASE, provider API keys, AI tuning varsTrigger.dev project Environment Variables, or synced by trigger.config.ts syncEnvVars

Production Env Vars (Trigger.dev Cloud Task Runtime)

After deployment, tasks run on Trigger.dev cloud. Configure these in Trigger.dev project Environment Variables for prod:

VariableRequiredPurpose
DATABASE_URLYesRead/write task, billing, and recovery data
S3_ENDPOINTYesObject storage endpoint
S3_REGIONYesObject storage region
S3_ACCESS_KEYYesObject storage key
S3_SECRET_KEYYesObject storage secret
S3_BUCKETYesOutput bucket
PUBLIC_S3_URL_BASEYesPublic output URL base; legacy NEXT_PUBLIC_S3_URL_BASE still works
SITE_URLRecommendedUsed when absolute links are generated
PUBLIC_AUTH_PROVIDERRecommendedKeeps auth provider selection consistent if auth code is imported
AUTH_SECRET / BETTER_AUTH_SECRETRecommended for Better AuthMay be needed if auth-related code is imported by tasks

Provider-specific vars (only for enabled providers):

VariableNeeded when
FAL_API_KEYUsing fal provider
REPLICATE_API_TOKENUsing replicate provider
KIE_API_KEYUsing kie provider
KIE_API_BASE_URLOptional override for kie API base URL
OPENAI_API_KEYCMS/admin AI copilot
OPENAI_API_BASEOptional OpenAI-compatible base URL
OPENAI_API_MODELOptional default model override

Optional tuning vars:

VariableDefaultPurpose
AI_TASK_RETRY_BASE_DELAY_MS2000Base retry delay
AI_TASK_RETRY_MAX_DELAY_MS60000Maximum retry delay
AI_TRIGGER_RUN_GUARD_TIMEOUT_MS270000Trigger task execution guard timeout
AI_TRIGGER_RELEASE_TIMEOUT_MS2000Timeout for releasing concurrency slots
AI_OUTBOX_WORKER_ENABLED1Set 0 to disable the outbox worker
AI_TASK_HEARTBEAT_AUDIT1Set 0 to disable heartbeat audit

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

  1. Ensure REDIS_URL is set and no TRIGGER_SECRET_KEY is present:
REDIS_URL=redis://your-redis-url:6379
  1. Deploy ship-api as a standalone server:
cd apps/ship-api
bun run src/index.ts

The 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.

BackendRecovery Mechanism
Trigger.devai-stale-recovery scheduled task (every 5 min, cloud)
BullMQsetInterval 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

Next Steps