Spaces:
Runtime error
Vault - Inngest Workflows
Generated: 2026-02-11
Framework: Inngest 3.49.1
Overview
Inngest provides durable workflow orchestration for long-running background tasks. All workflows are defined in src/inngest/.
Client Configuration
File: src/inngest/client.ts
import { Inngest } from 'inngest';
export const inngest = new Inngest({
id: 'vault',
name: 'Vault AI Discovery',
eventKey: process.env.INNGEST_EVENT_KEY,
});
Handler Registration
File: src/app/api/inngest/route.ts
import { serve } from 'inngest/next';
import { inngest } from '@/inngest/client';
import { scanVideoArchive } from '@/inngest/functions/scan-video-archive';
import { detectObjects } from '@/inngest/functions/detect-objects';
import { matchMarketplace } from '@/inngest/functions/match-marketplace';
import { monitorLinkHealth, checkSingleLinkHealth } from '@/inngest/functions/monitor-link-health';
import { warmFeaturedCreatorsCache } from '@/inngest/functions/warm-featured-creators-cache';
import { healSocialMetadata } from '@/inngest/functions/social-healing';
export const { GET, POST, PUT } = serve({
client: inngest,
functions: [
scanVideoArchive,
detectObjects,
matchMarketplace,
monitorLinkHealth,
checkSingleLinkHealth,
warmFeaturedCreatorsCache,
healSocialMetadata,
],
signingKey: process.env.INNGEST_SIGNING_KEY,
});
Workflow: Scan Video Archive
Function ID: scan-video-archive
File: src/inngest/functions/scan-video-archive.ts
Event: youtube/video-archive.scan
Purpose
Scans a YouTube channel's video archive, fetching metadata and queuing videos for object detection.
Event Payload
interface ScanVideoArchiveEvent {
name: 'youtube/video-archive.scan';
data: {
channelId: string; // Internal DB channel ID
userId: string; // User who initiated scan
scanJobId: string; // Progress tracking ID
};
}
Workflow Steps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β scan-video-archive β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Step 1: validate-channel β
β βββ Verify channel ownership β
β βββ Update syncStatus to 'syncing' β
β βββ Return channel data β
β β
β Step 2: fetch-refresh-token β
β βββ Get OAuth refresh token from accounts table β
β β
β Step 3: refresh-access-token β
β βββ Exchange refresh token for new access token β
β β
β Step 4: get-uploads-playlist β
β βββ Fetch channel's uploads playlist ID β
β β
β Step 5: fetch-video-ids (paginated) β
β βββ Get all video IDs from playlist β
β β
β Step 6: fetch-video-metadata (batched) β
β βββ Get metadata for each video β
β β
β Step 7: store-videos β
β βββ Insert/update videos in database β
β β
β Step 8: trigger-detection (per video) β
β βββ Send 'youtube/video.detect-objects' event β
β β
β Step 9: update-scan-job β
β βββ Mark scan job as completed β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Error Handling
- NonRetriableError: Channel not found, access denied
- RetryAfterError: YouTube API rate limits
- onFailure: Update scan job status to 'failed', set channel syncStatus to 'errored'
Workflow: Detect Objects
Function ID: detect-objects
File: src/inngest/functions/detect-objects.ts
Event: youtube/video.detect-objects
Purpose
Extracts frames from a video and runs AI object detection on each frame.
Event Payload
interface DetectObjectsEvent {
name: 'youtube/video.detect-objects';
data: {
videoId: string; // Internal DB video ID
videoUrl: string; // Video URL for processing
};
}
Workflow Steps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β detect-objects β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Step 1: update-scan-status-started β
β βββ Set video scanStatus to 'in_progress' β
β β
β Step 2: analyze-video-content β
β βββ Calculate adaptive frame interval β
β β βββ 0-2 min: every 5 seconds β
β β βββ 2-5 min: every 10 seconds β
β β βββ 5-10 min: every 15 seconds β
β β βββ 10+ min: every 30 seconds β
β βββ Extract frames at intervals (FFmpeg) β
β βββ Process frames in batches of 3 β
β βββ Run AI detection on each frame β
β βββ Generate thumbnails for detections β
β βββ Return all detection results β
β β
β Step 3: store-detections β
β βββ Insert detected objects into database β
β β
β Step 4: trigger-marketplace-matching β
β βββ Send 'discovery/objects.match-marketplace' event β
β β
β Step 5: update-scan-status-completed β
β βββ Set video scanStatus to 'awaiting_approval' β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
AI Vision Providers
Configured via VISION_PROVIDER environment variable:
| Provider | Model | Best For |
|---|---|---|
gemini |
Gemini Flash | Complex scenes, good accuracy |
huggingface |
DETR | Specialized object detection, better free tier |
Error Handling
- VideoUnavailableError: Video is private or deleted
- VisionRateLimitError: AI provider rate limits
- NonRetriableError: Missing videoId or videoUrl
Workflow: Match Marketplace
Function ID: match-marketplace
File: src/inngest/functions/match-marketplace.ts
Event: discovery/objects.match-marketplace
Purpose
Searches Amazon, eBay, and Etsy for products matching detected objects.
Event Payload
interface MatchMarketplaceEvent {
name: 'discovery/objects.match-marketplace';
data: {
detectedObjectId?: string; // Single ID (legacy)
detectedObjectIds?: string[]; // Batch IDs (preferred)
};
}
Workflow Steps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β match-marketplace β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β For each detected object: β
β β
β Step 1: fetch-object-{id} β
β βββ Get detection details from database β
β β
β Step 2: search-amazon-{id} β
β βββ Check cache for existing matches β
β βββ If not cached, search Amazon PA-API β
β βββ Cache results β
β βββ Return matches β
β β
β Step 3: search-ebay-{id} β
β βββ Check cache for existing matches β
β βββ If not cached, search eBay Finding API β
β βββ Cache results β
β βββ Return matches β
β β
β Step 4: search-etsy-{id} β
β βββ Check cache for existing matches β
β βββ If not cached, search Etsy Open API β
β βββ Cache results β
β βββ Return matches β
β β
β Step 5: store-matches-{id} β
β βββ Insert marketplace matches into database β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Caching Strategy
- Cache Key:
{objectId}:{marketplace} - TTL: 24 hours
- Storage: Upstash Redis
Rate Limit Handling
- MarketplaceRateLimitError: Triggers
RetryAfterError - Automatic retry after specified delay
Workflow: Monitor Link Health
Function ID: monitor-link-health
File: src/inngest/functions/monitor-link-health.ts
Event: marketplace/links.health-check
Purpose
Periodically checks affiliate links for availability and updates status.
Event Payload
interface MonitorLinkHealthEvent {
name: 'marketplace/links.health-check';
data: {
matchId?: string; // Single match check
checkAll?: boolean; // Check all active links
};
}
Workflow Steps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β monitor-link-health β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Step 1: fetch-links-to-check β
β βββ Get links with status 'ACTIVE' or 'CHECKING' β
β β
β For each link: β
β β
β Step 2: check-link-{id} β
β βββ HTTP HEAD request to affiliate URL β
β βββ Record HTTP status β
β βββ Return status β
β β
β Step 3: update-link-status-{id} β
β βββ If 200: Set status 'ACTIVE' β
β βββ If 404: Set status 'BROKEN' β
β βββ Increment checkAttempts β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Link Status Transitions
ACTIVE ββcheckββ> CHECKING ββsuccessββ> ACTIVE
β
βββfailureββ> BROKEN
Workflow: Warm Featured Creators Cache
Function ID: warm-featured-creators-cache
File: src/inngest/functions/warm-featured-creators-cache.ts
Event: cache/warm-featured-creators
Purpose
Pre-warms cache for featured creators on the homepage.
Workflow Steps
- Fetch featured creators from database
- For each creator, fetch their vault data
- Store in Redis cache with TTL
Workflow: Heal Social Metadata
Function ID: heal-social-metadata
File: src/inngest/functions/social-healing.ts
Event: social/metadata.heal
Purpose
Repairs inconsistent platform metadata for multi-platform content.
Workflow Steps
- Find videos with platform mismatches
- Update platform field based on video ID patterns
- Update channel platform associations
Error Handling Patterns
NonRetriableError
For errors that should not be retried:
import { NonRetriableError } from 'inngest';
throw new NonRetriableError('Channel not found or access denied');
RetryAfterError
For rate-limited resources:
import { RetryAfterError } from 'inngest';
throw new RetryAfterError('Amazon rate limit exceeded', '60s');
Sentry Integration
All functions capture errors with Sentry:
import * as Sentry from '@sentry/nextjs';
onFailure: async ({ event, error }) => {
Sentry.captureException(error, {
tags: {
source: 'inngest',
function: 'function-name',
type: 'function_failure',
},
extra: { event: event.data },
});
}
Development & Testing
Local Development
Start Inngest Dev Server:
npx inngest-cli devApplication connects to dev server automatically in development mode.
Manual Triggers
Use the manual trigger endpoint for testing:
curl -X POST http://localhost:3000/api/manual-trigger \
-H "Content-Type: application/json" \
-d '{"function": "scan-video-archive", "data": {...}}'
Monitoring
- Inngest Cloud Dashboard: View function runs, retries, errors
- Sentry: Error tracking with context
- Logs: Console output captured in Inngest dashboard
Related Documentation
- API Contracts - Server actions and endpoints
- Data Models - Database schema
- Development Guide - Setup instructions