Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa

Escalonamento

Escalone o Nodaro self-hosted para além de um contêiner: separe a API, os workers e o orquestrador e ajuste a concorrência, o Redis e o armazenamento.

Escalonar um Nodaro self-hosted significa rodar os processos dele em mais de um contêiner. A configuração padrão do Compose roda tudo em um único contêiner: a API, os workers, o orquestrador e o servidor web. Isso atende bem até cerca de 5 usuários ativos. Para mais usuários, rode os workers em contêineres próprios. Eles compartilham um Redis, um banco de dados e um bucket de armazenamento, e só se coordenam pelas filas do Redis.

Os processos

O script de inicialização da imagem, /app/start.sh, inicia estes processos lado a lado, a partir de /app/backend:

ComandoO que fazCarga
node dist/server.jsA API HTTPPouca CPU, memória moderada
node dist/worker.jsO worker de mídia: um job por nó, chama os provedores de modelosEspera pela rede, executa muitos jobs ao mesmo tempo
node dist/render-worker.jsO renderizador: composições, em um Chrome headlessLimitado pela CPU: 1 ou 2 por máquina
node dist/orchestrator.jsO orquestrador de workflows: executa o grafo de cada workflowEspera pela rede, pouca CPU
node dist/pipeline-worker.jsO pipeline História → vídeo (Story → Video), que só roda no Nodaro CloudEncerra na hora nas edições self-hosted

O script de inicialização também faz quatro coisas que um contêiner que roda um único processo não faz:

  • Ele roda o servidor web na porta 3000, na frente da API.
  • Ele aplica as migrações na stack incluída.
  • Ele gera o INTERNAL_ORCHESTRATOR_SECRET quando a variável não está definida.
  • Ele gera a chave de criptografia na stack incluída.

Leia o script na imagem antes de dividi-lo.

Uma divisão típica

  • 1 contêiner da API, rodando server.js.
  • Vários contêineres de worker de mídia. VIDEO_WORKER_CONCURRENCY=50, o padrão, serve para cada um.
  • 1 ou 2 contêineres de worker de renderização, cada um na própria máquina.
  • 1 contêiner do orquestrador.

Os contêineres nunca se comunicam diretamente. Todos usam o mesmo Redis, o mesmo Supabase e o mesmo armazenamento, e o Redis é o único ponto de coordenação.

O que todos os contêineres precisam compartilhar

VariávelPor que precisa ser igual
INTERNAL_ORCHESTRATOR_SECRETO orquestrador se autentica na API com ela. O script de inicialização gera uma nova em cada contêiner quando ela não está definida, então defina-a explicitamente, com o mesmo valor em todos os lugares.
NODARO_ENCRYPTION_KEYAs chaves de provedor e as credenciais armazenadas são criptografadas com ela. Outra chave não consegue lê-las.
RUNTIME_ENVDá nome à instalação. Todos os contêineres de uma mesma instalação precisam usar o mesmo valor.
EDITION, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, REDIS_URL e as variáveis R2_*A mesma edição, o mesmo banco de dados, as mesmas filas e o mesmo armazenamento em todos os contêineres.

Concorrência

VariávelPadrãoO que ela limita
MAX_CONCURRENT_NODES_PER_EXECUTION6, no máximo 20Os nós que uma execução de workflow pode executar ao mesmo tempo. O teto de nós em paralelo para todo o servidor.
VIDEO_WORKER_CONCURRENCY50Jobs ao mesmo tempo em um worker de mídia
ORCHESTRATOR_CONCURRENCY20Jobs de workflow ao mesmo tempo em um orquestrador
RENDER_WORKER_CONCURRENCY2, no máximo 10Renderizações ao mesmo tempo em um worker de renderização. Cada uma é um Chrome headless.
REMOTION_CONCURRENCY2 para cenas 3D; metade dos núcleos da CPU para as outras renderizaçõesAbas do navegador por renderização. Mantenha o valor baixo quando vários jobs 3D são executados ao mesmo tempo: cada aba WebGL acrescenta threads e conta para o limite de processos do contêiner.
FFMPEG_CONCURRENCY4, no máximo 32Processos do ffmpeg ao mesmo tempo, somando todos os nós de edição de vídeo e de áudio

O arquivo do Compose não repassa essas variáveis do .env. Adicione-as em environment: de cada serviço que precisa delas.

Cada nó de uma execução pode levar até 90 minutos, e uma execução inteira, até 120 minutos. Um nó que declara o próprio orçamento de tempo recebe esse orçamento, e o limite da execução cresce na mesma medida. O Aplicar EDL (Apply EDL) é um nó assim: o orçamento dele depende da edição que ele renderiza.

Alta disponibilidade do Redis

As filas de jobs aceitam o modo cluster do Redis. Defina REDIS_URL com um endpoint de cluster ou uma URL do Sentinel.

Além das filas, a API mantém pequenos caches compartilhados no Redis, para que vários contêineres da API não repitam, cada um, o mesmo trabalho lento junto aos provedores. Hoje, isso é o catálogo de avatares e vozes da HeyGen, de cerca de 4 MB. Um contêiner o atualiza sob um bloqueio (lock) a cada HEYGEN_CATALOG_REFRESH_HOURS horas, 24 por padrão, e os outros adotam a nova cópia em cerca de meio minuto. Tudo ali é cache: quando o Redis não pode ser acessado, cada contêiner usa a própria memória, e uma entrada perdida é preenchida de novo a partir do provedor na inicialização seguinte.

Duas instalações, um banco de dados

Você pode apontar uma segunda instalação, como uma cópia de staging, para o mesmo projeto do Supabase, com um Redis próprio. Nesse caso, dê a cada instalação um RUNTIME_ENV diferente. No Railway, RAILWAY_ENVIRONMENT_NAME já faz isso.

Cada execução registra o nome da instalação cujo orquestrador a assumiu, e a limpeza de cada instalação só verifica as próprias execuções. Sem nomes distintos, cada instalação procura no próprio Redis os jobs da outra, não os encontra e marca execuções saudáveis como falhas com Execution orphaned. As execuções que começaram antes de as instalações registrarem os nomes não têm nome; a instalação chamada production cuida delas.

Ciclo de vida do armazenamento

O Nodaro nunca apaga sozinho a mídia armazenada: ele só faz referência aos arquivos pela chave deles. Para expirar a mídia antiga, adicione uma regra de ciclo de vida ao seu bucket, por exemplo depois de 90 dias. Inclua o prefixo video-analysis-tmp/ na regra: ele guarda arquivos temporários de análise, e as instalações self-hosted não têm um job de limpeza para eles.

Parar contêineres no Railway

No Railway, RAILWAY_DEPLOYMENT_DRAINING_SECONDS define o tempo entre o sinal de parada e a parada forçada de um contêiner substituído. O worker de mídia drena durante esse tempo menos 5 segundos, para que uma chamada longa a um modelo consiga terminar e ser salva antes de o job dela passar para o novo contêiner. Sem a variável, o worker drena por 25 segundos.

Perguntas frequentes

Última atualização

Nesta página