> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shappire.tools/llms.txt
> Use this file to discover all available pages before exploring further.

# Worker em background

> Arquitetura com fila, worker e storage próprio

## Arquitetura recomendada

```
Cliente → sua API → fila (Redis/SQS) → Worker → Shappire API → S3/R2
```

## Por que fila?

* Limite de **2 jobs simultâneos** por projeto
* Downloads demoram — não bloqueie HTTP do usuário
* Retry automático em falhas transitórias

## Fluxo do worker

<Steps>
  <Step title="Receber job da fila">
    Payload: `{ "url": "...", "format": "video_best", "userId": "..." }`
  </Step>

  <Step title="Resolve (se necessário)">
    `POST /media/resolve` → `media_id`
  </Step>

  <Step title="Enfileirar download">
    `POST /media/download` → `job_id`
  </Step>

  <Step title="Polling">
    `GET /jobs/{id}` até `completed`
  </Step>

  <Step title="Persistir">
    Baixar `download_url` → upload S3 → salvar URL permanente no DB
  </Step>
</Steps>

## Exemplo BullMQ (Node.js)

```javascript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
import { Queue, Worker } from 'bullmq';

const queue = new Queue('media-downloads');

export async function scheduleDownload(url, userId) {
  await queue.add('download', { url, userId });
}

new Worker('media-downloads', async (job) => {
  const media = await resolveMedia(job.data.url);
  const jobId = await enqueueDownload(media.id, 'video_best');
  const result = await waitForJob(jobId);
  await uploadToS3(result.result.download_url, job.data.userId);
});
```

## Concorrência

Configure no máximo **2 workers** fazendo download Shappire ao mesmo tempo por projeto — ou use semáforo global.
