본문으로 건너뛰기
cccskills
무료GitHub에 공개

trigger-advanced-tasks

Apply advanced Trigger.dev task patterns for concurrency, retries, idempotency, progress tracking, machine sizing, and run management. The guidance helps structure resilient tasks and monitor execution details, including cost, duration, logs, and child task progress.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

Comprehensive rules to help you write advanced Trigger.dev tasks

trycompai/comp스타 2,061(GitHub 2,061 + cccskills 0)

실행 점수 미검증

설치 방법 보기

이럴 때 유용합니다

  • Limiting task concurrency with queues
  • Configuring retries and fatal error handling
  • Preventing duplicate payment or critical operations
  • Tracking progress in a long-running task
  • Monitoring run cost and duration

포함된 파일(1)

  • SKILL.md11.4 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Source Cursor rule: .cursor/rules/trigger.advanced-tasks.mdc. Original file scope: **/trigger/**/*.ts. Original Cursor alwaysApply: false.

Trigger.dev Advanced Tasks (v4)

Advanced patterns and features for writing tasks

Tags & Organization

import { task, tags } from '@trigger.dev/sdk';

export const processUser = task({
  id: 'process-user',
  run: async (payload: { userId: string; orgId: string }, { ctx }) => {
    // Add tags during execution
    await tags.add(`user_${payload.userId}`);
    await tags.add(`org_${payload.orgId}`);

    return { processed: true };
  },
});

// Trigger with tags
await processUser.trigger(
  { userId: '123', orgId: 'abc' },
  { tags: ['priority', 'user_123', 'org_abc'] }, // Max 10 tags per run
);

// Subscribe to tagged runs
for await (const run of runs.subscribeToRunsWithTag('user_123')) {
  console.log(`User task ${run.id}: ${run.status}`);
}

Tag Best Practices:

  • Use prefixes: user_123, org_abc, video:456
  • Max 10 tags per run, 1-128 characters each
  • Tags don't propagate to child tasks automatically

Concurrency & Queues

import { task, queue } from '@trigger.dev/sdk';

// Shared queue for related tasks
const emailQueue = queue({
  name: 'email-processing',
  concurrencyLimit: 5, // Max 5 emails processing simultaneously
});

// Task-level concurrency
export const oneAtATime = task({
  id: 'sequential-task',
  queue: { concurrencyLimit: 1 }, // Process one at a time
  run: async (payload) => {
    // Critical section - only one instance runs
  },
});

// Per-user concurrency
export const processUserData = task({
  id: 'process-user-data',
  run: async (payload: { userId: string }) => {
    // Override queue with user-specific concurrency
    await childTask.trigger(payload, {
      queue: {
        name: `user-${payload.userId}`,
        concurrencyLimit: 2,
      },
    });
  },
});

export const emailTask = task({
  id: 'send-email',
  queue: emailQueue, // Use shared queue
  run: async (payload: { to: string }) => {
    // Send email logic
  },
});

Error Handling & Retries

import { task, retry, AbortTaskRunError } from '@trigger.dev/sdk';

export const resilientTask = task({
  id: 'resilient-task',
  retry: {
    maxAttempts: 10,
    factor: 1.8, // Exponential backoff multiplier
    minTimeoutInMs: 500,
    maxTimeoutInMs: 30_000,
    randomize: false,
  },
  catchError: async ({ error, ctx }) => {
    // Custom error handling
    if (error.code === 'FATAL_ERROR') {
      throw new AbortTaskRunError('Cannot retry this error');
    }

    // Log error details
    console.error(`Task ${ctx.task.id} failed:`, error);

    // Allow retry by returning nothing
    return { retryAt: new Date(Date.now() + 60000) }; // Retry in 1 minute
  },
  run: async (payload) => {
    // Retry specific operations
    const result = await retry.onThrow(
      async () => {
        return await unstableApiCall(payload);
      },
      { maxAttempts: 3 },
    );

    // Conditional HTTP retries
    const response = await retry.fetch('https://api.example.com', {
      retry: {
        maxAttempts: 5,
        condition: (response, error) => {
          return response?.status === 429 || response?.status >= 500;
        },
      },
    });

    return result;
  },
});

Machines & Performance

export const heavyTask = task({
  id: 'heavy-computation',
  machine: { preset: 'large-2x' }, // 8 vCPU, 16 GB RAM
  maxDuration: 1800, // 30 minutes timeout
  run: async (payload, { ctx }) => {
    // Resource-intensive computation
    if (ctx.machine.preset === 'large-2x') {
      // Use all available cores
      return await parallelProcessing(payload);
    }

    return await standardProcessing(payload);
  },
});

// Override machine when triggering
await heavyTask.trigger(payload, {
  machine: { preset: 'medium-1x' }, // Override for this run
});

Machine Presets:

  • micro: 0.25 vCPU, 0.25 GB RAM
  • small-1x: 0.5 vCPU, 0.5 GB RAM (default)
  • small-2x: 1 vCPU, 1 GB RAM
  • medium-1x: 1 vCPU, 2 GB RAM
  • medium-2x: 2 vCPU, 4 GB RAM
  • large-1x: 4 vCPU, 8 GB RAM
  • large-2x: 8 vCPU, 16 GB RAM

Idempotency

import { task, idempotencyKeys } from '@trigger.dev/sdk';

export const paymentTask = task({
  id: 'process-payment',
  retry: {
    maxAttempts: 3,
  },
  run: async (payload: { orderId: string; amount: number }) => {
    // Automatically scoped to this task run, so if the task is retried, the idempotency key will be the same
    const idempotencyKey = await idempotencyKeys.create(`payment-${payload.orderId}`);

    // Ensure payment is processed only once
    await chargeCustomer.trigger(payload, {
      idempotencyKey,
      idempotencyKeyTTL: '24h', // Key expires in 24 hours
    });
  },
});

// Payload-based idempotency
import { createHash } from 'node:crypto';

function createPayloadHash(payload: any): string {
  const hash = createHash('sha256');
  hash.update(JSON.stringify(payload));
  return hash.digest('hex');
}

export const deduplicatedTask = task({
  id: 'deduplicated-task',
  run: async (payload) => {
    const payloadHash = createPayloadHash(payload);
    const idempotencyKey = await idempotencyKeys.create(payloadHash);

    await processData.trigger(payload, { idempotencyKey });
  },
});

Metadata & Progress Tracking

import { task, metadata } from '@trigger.dev/sdk';

export const batchProcessor = task({
  id: 'batch-processor',
  run: async (payload: { items: any[] }, { ctx }) => {
    const totalItems = payload.items.length;

    // Initialize progress metadata
    metadata
      .set('progress', 0)
      .set('totalItems', totalItems)
      .set('processedItems', 0)
      .set('status', 'starting');

    const results = [];

    for (let i = 0; i < payload.items.length; i++) {
      const item = payload.items[i];

      // Process item
      const result = await processItem(item);
      results.push(result);

      // Update progress
      const progress = ((i + 1) / totalItems) * 100;
      metadata
        .set('progress', progress)
        .increment('processedItems', 1)
        .append('logs', `Processed item ${i + 1}/${totalItems}`)
        .set('currentItem', item.id);
    }

    // Final status
    metadata.set('status', 'completed');

    return { results, totalProcessed: results.length };
  },
});

// Update parent metadata from child task
export const childTask = task({
  id: 'child-task',
  run: async (payload, { ctx }) => {
    // Update parent task metadata
    metadata.parent.set('childStatus', 'processing');
    metadata.root.increment('childrenCompleted', 1);

    return { processed: true };
  },
});

Advanced Triggering

Frontend Triggering (React)

'use client';
import { useTaskTrigger } from '@trigger.dev/react-hooks';
import type { myTask } from '../trigger/tasks';

function TriggerButton({ accessToken }: { accessToken: string }) {
  const { submit, handle, isLoading } = useTaskTrigger<typeof myTask>('my-task', { accessToken });

  return (
    <button onClick={() => submit({ data: 'from frontend' })} disabled={isLoading}>
      Trigger Task
    </button>
  );
}

Large Payloads

// For payloads > 512KB (max 10MB)
export const largeDataTask = task({
  id: 'large-data-task',
  run: async (payload: { dataUrl: string }) => {
    // Trigger.dev automatically handles large payloads
    // For > 10MB, use external storage
    const response = await fetch(payload.dataUrl);
    const largeData = await response.json();

    return { processed: largeData.length };
  },
});

// Best practice: Use presigned URLs for very large files
await largeDataTask.trigger({
  dataUrl: 'https://s3.amazonaws.com/bucket/large-file.json?presigned=true',
});

Advanced Options

await myTask.trigger(payload, {
  delay: '2h30m', // Delay execution
  ttl: '24h', // Expire if not started within 24 hours
  priority: 100, // Higher priority (time offset in seconds)
  tags: ['urgent', 'user_123'],
  metadata: { source: 'api', version: 'v2' },
  queue: {
    name: 'priority-queue',
    concurrencyLimit: 10,
  },
  idempotencyKey: 'unique-operation-id',
  idempotencyKeyTTL: '1h',
  machine: { preset: 'large-1x' },
  maxAttempts: 5,
});

Hidden Tasks

// Hidden task - not exported, only used internally
const internalProcessor = task({
  id: 'internal-processor',
  run: async (payload: { data: string }) => {
    return { processed: payload.data.toUpperCase() };
  },
});

// Public task that uses hidden task
export const publicWorkflow = task({
  id: 'public-workflow',
  run: async (payload: { input: string }) => {
    // Use hidden task internally
    const result = await internalProcessor.triggerAndWait({
      data: payload.input,
    });

    if (result.ok) {
      return { output: result.output.processed };
    }

    throw new Error('Internal processing failed');
  },
});

Logging & Tracing

import { task, logger } from '@trigger.dev/sdk';

export const tracedTask = task({
  id: 'traced-task',
  run: async (payload, { ctx }) => {
    logger.info('Task started', { userId: payload.userId });

    // Custom trace with attributes
    const user = await logger.trace(
      'fetch-user',
      async (span) => {
        span.setAttribute('user.id', payload.userId);
        span.setAttribute('operation', 'database-fetch');

        const userData = await database.findUser(payload.userId);
        span.setAttribute('user.found', !!userData);

        return userData;
      },
      { userId: payload.userId },
    );

    logger.debug('User fetched', { user: user.id });

    try {
      const result = await processUser(user);
      logger.info('Processing completed', { result });
      return result;
    } catch (error) {
      logger.error('Processing failed', {
        error: error.message,
        userId: payload.userId,
      });
      throw error;
    }
  },
});

Usage Monitoring

import { logger, task, usage } from '@trigger.dev/sdk';

export const monitoredTask = task({
  id: 'monitored-task',
  run: async (payload) => {
    // Get current run cost
    const currentUsage = await usage.getCurrent();
    logger.info('Current cost', {
      costInCents: currentUsage.costInCents,
      durationMs: currentUsage.durationMs,
    });

    // Measure specific operation
    const { result, compute } = await usage.measure(async () => {
      return await expensiveOperation(payload);
    });

    logger.info('Operation cost', {
      costInCents: compute.costInCents,
      durationMs: compute.durationMs,
    });

    return result;
  },
});

Run Management

// Cancel runs
await runs.cancel('run_123');

// Replay runs with same payload
await runs.replay('run_123');

// Retrieve run with cost details
const run = await runs.retrieve('run_123');
console.log(`Cost: ${run.costInCents} cents, Duration: ${run.durationMs}ms`);

Best Practices

  • Concurrency: Use queues to prevent overwhelming external services
  • Retries: Configure exponential backoff for transient failures
  • Idempotency: Always use for payment/critical operations
  • Metadata: Track progress for long-running tasks
  • Machines: Match machine size to computational requirements
  • Tags: Use consistent naming patterns for filtering
  • Large Payloads: Use external storage for files > 10MB
  • Error Handling: Distinguish between retryable and fatal errors

Design tasks to be stateless, idempotent, and resilient to failures. Use metadata for state tracking and queues for resource management.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Guide API endpoint changes so request DTOs, runtime validation, OpenAPI documentation, and MCP tool metadata stay aligned. It covers discoverability, authentication, uploads, long-running tasks, and response types that MCP tools cannot handle.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Adding an API endpoint with a request body
  • Updating DTO validation and OpenAPI metadata
  • Making an endpoint available as an MCP tool
trycompai/comp2.1천2026년 10월 24일 업데이트

Review specified files for design system usage, replace legacy @trycompai/ui components and lucide-react icons with available @trycompai/design-system equivalents, and run the app type check to verify the migration.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Migrating legacy UI components
  • Replacing lucide-react icons with Carbon icons
  • Checking specified files for design system compliance
trycompai/comp2.1천2026년 10월 24일 업데이트

Review specified files for outdated hook and API patterns, then replace them with the prescribed SWR hooks, API clients, or server API calls. The guidance covers data fetching, mutations, cache updates, and response handling, followed by a typecheck command.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Auditing files for disallowed API and hook patterns
  • Replacing raw fetch calls with the API client
  • Migrating server actions and database mutations to API hooks
trycompai/comp2.1천2026년 10월 24일 업데이트

Review NestJS API endpoints and frontend components for role-based access control and audit log compliance. The skill lists permission, guard, route, and UI gating rules, then directs the agent to fix violations and run type checks.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Auditing API routes for permission decorators
  • Checking UI actions against user permissions
  • Fixing access control inconsistencies
trycompai/comp2.1천2026년 10월 24일 업데이트

Audit unit tests for components that use permissions. Add missing tests and fix failures, checking that administrators can use mutation controls, auditors cannot, and read-only content remains visible to both.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Adding permission tests for a component
  • Checking admin and auditor behavior
  • Fixing failing permission-related tests
trycompai/comp2.1천2026년 10월 24일 업데이트

Set up Better Auth for TypeScript applications, including server and client configuration, database adapters, sessions, email and social sign-in, and plugins. The guide also highlights environment variables, schema generation, and security settings to review.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Configuring Better Auth in a TypeScript app
  • Connecting an ORM or database adapter
  • Setting up sessions and cookie storage
trycompai/comp2.1천2026년 10월 24일 업데이트

trycompai의 스킬 모두 보기

이 스킬의 문제 신고