Executar código
Use esta ação quando um passo precisar de lógica personalizada que o CEL não consegue expressar — reformatar dados, calcular valores, processar arquivos ou chamar uma API com código. Uma única ação cobre as duas linguagens: escolha JavaScript ou Python no campo Linguagem.
Melhor para
- Transformar JSON de passos anteriores exatamente no formato de que um passo posterior precisa
- Cálculos, parsing e validações além do que expressões CEL conseguem fazer
- Pequenas integrações usando
fetch(JavaScript) quando a ação Requisição HTTP não for flexível o suficiente - Trabalho com documentos e arquivos usando as bibliotecas incluídas do Python — planilhas, PDFs, imagens, DOCX/PPTX
Escolhendo a linguagem
| JavaScript | Python | |
|---|---|---|
| Runtime | Sandbox V8 isolado (sem APIs do Node.js) | Python 3.12 em um container descartável |
| Rede | fetch com proteção SSRF | Nenhuma — por design |
| Tempo limite (ms) | 100–30.000, padrão 5.000 | 1.000–120.000, padrão 30.000 |
| Memória (MB) | 8–256, padrão 128 | 128–2.048, padrão 512 |
| Bibliotecas | Recursos padrão do JavaScript | openpyxl, python-docx, python-pptx, pdfplumber, pypdf, pandas, Pillow, reportlab, markitdown — sem pip em tempo de execução |
As duas linguagens compartilham as mesmas entradas e saídas: Dados de entrada estruturados, Arquivos de entrada, um resultado estruturado, arquivos de saída e logs em um formato unificado.
Campos principais
| Campo | O que faz |
|---|---|
| Linguagem | javascript (padrão) ou python |
| Código | O código a executar. JavaScript é envolvido em uma IIFE assíncrona, então você pode usar await no nível superior e terminar com return <valor>. Python executa como um script comum; escreva o resultado em /work/out/output.json |
| Dados de entrada | Expressão CEL opcional avaliada antes da execução. JavaScript vê o valor na variável input; Python vê na variável INPUT |
| Arquivos de entrada | Expressão CEL opcional que avalia para um array de referências de storage [{bucket, fullPath, name?}] — por exemplo step(0).files ou um input de workflow do tipo arquivo. O conteúdo dos arquivos é entregue ao sandbox; o código nunca acessa o storage diretamente |
| Propósito | Rótulo opcional do que o código faz, exibido nos logs |
| Tempo limite (ms) | Limite de tempo de execução em milissegundos, restrito por linguagem (veja a tabela acima). Código que ultrapassa o limite — incluindo loops infinitos — é encerrado |
| Limite de memória (MB) | Limite de memória do sandbox, restrito por linguagem |
Arquivos de entrada e de saída
As duas direções compartilham os mesmos limites: no máximo 10 arquivos, 20 MiB por arquivo, 24 MiB no total. Nomes de arquivo devem começar com letra ou dígito e podem conter letras, dígitos, ., _, - e espaços (até 128 caracteres). Os nomes input.json e output.json são reservados — eles são os canais de dados estruturados.
Lendo arquivos de entrada:
- JavaScript —
files.readText(name)retorna o conteúdo como string de texto (decodificado como UTF-8);files.read(name)retorna como string base64, para dados binários - Python — os arquivos aparecem em
/work/in/<nome>(somente leitura)
Escrevendo arquivos de saída:
- JavaScript —
files.writeText(name, text, {contentType?})para texto;files.write(name, contentBase64, {contentType?})para binário.contentTypeé inferido da extensão quando omitido - Python — escreva os arquivos em
/work/out/
Para trabalhar com texto — CSV, JSON, Markdown — use readText / writeText e dispense o base64:
const rows = files.readText("data.csv").split("\n").map((line) => line.split(","));
files.writeText("summary.txt", `${rows.length} linhas`);
O par base64 existe para arquivos binários (imagens, PDFs, planilhas), normalmente para repassar os bytes sem alteração ou entregá-los ao fetch.
Os arquivos de saída são enviados ao storage da sua empresa após a execução e aparecem como referências de storage em step(N).files. Passos posteriores podem encadeá-los — por exemplo, um passo Python cujos Arquivos de entrada sejam step(0).files lê tudo o que o passo de código anterior produziu.
O sandbox JavaScript
O código executa em um sandbox V8 isolado em um serviço de execução separado. Não há acesso a APIs do Node.js (require, process, sistema de arquivos) nem a APIs de navegador — apenas os recursos padrão do JavaScript mais estas pontes:
input— o valor avaliado de Dados de entrada (nullquando ausente)console.log/info/warn/error— capturados e retornados na saídalogsfetch(url, options)— HTTP com proteção SSRF (endereços privados e internos são bloqueados) que retorna{ok, status, statusText, body}, combodyinterpretado como JSON quando possível e retornado como texto caso contrário. Corpos de resposta são limitados a 10 MiB — uma resposta maior falha a etapa em vez de ser carregada na memóriafiles.read/files.readText/files.write/files.writeText— veja acimaatob(base64)/btoa(binaryString)— o codec base64 padrão, para converter os valores com quefiles.readefiles.writetrabalham.btoasegue a regra da web de rejeitar caracteres acima deU+00FF, então usefiles.writeTextpara texto UTF-8 em vez debtoa
Não existe Buffer, nem TextDecoder/TextEncoder, nem require — atob/btoa e os helpers de texto de files são a forma suportada de converter entre bytes e strings.
O sandbox Python
O código executa como python3 job.py em um container novo que é destruído após a execução:
- Sem acesso à rede — deliberado. Use a linguagem JavaScript para chamadas HTTP
INPUT— o valor avaliado de Dados de entrada, carregado de/work/in/input.json(Nonequando ausente)- Arquivos de entrada em
/work/in/(somente leitura), arquivos de saída em/work/out/ - Escreva o resultado estruturado do passo como JSON em
/work/out/output.json— é isso questep(N).resultrecebe.print()vai para a saídalogs, não para o resultado. Um job que não escreveoutput.jsonrecebestep(N).result=null - Apenas as bibliotecas incluídas listadas acima são importáveis — não há
pipem tempo de execução - Apenas um job Python executa por vez; um runner ocupado falha o passo com um erro com retry (veja abaixo)
O que passos posteriores podem usar
step(N).result— o resultado estruturado (valor doreturnem JavaScript /output.jsonem Python), limitado a 2 MiB — escreva dados volumosos como arquivos.nullquando o código não retornou nada / não escreveuoutput.jsonstep(N).files— referências de storage dos arquivos que o código escreveu:[{name, bucket, fullPath, contentType, size}]step(N).logs— saída capturada como entradas[{level, message}](níveis de console no JavaScript;stdout/stderrno Python), até 200 entradas de 2.000 caracteres cadastep(N).executionTimeMs— quanto tempo o código executou
Versões anteriores expunham o valor de retorno do JavaScript como
step(N).data. Agora éstep(N).result, para as duas linguagens.
Erros
| Código | Significado |
|---|---|
code_execution_failed | O código lançou uma exceção — verifique step(N).logs |
code_execution_timeout | O código ultrapassou o tempo limite (ambas as linguagens) |
code_executor_busy | O único slot do runner Python está ocupado — com retry; executar o passo novamente é seguro |
code_result_too_large | O resultado serializado passa de 2 MiB — retorne um resumo pequeno e escreva dados volumosos como arquivos |
code_result_invalid_json | Python escreveu /work/out/output.json, mas não é JSON válido |
code_input_files_invalid | Arquivos de entrada não avaliou para referências válidas, ultrapassou os limites ou usou um nome reservado |
code_input_file_not_accessible | Um arquivo de entrada não foi encontrado ou não está acessível a partir deste workspace |
code_input_file_unavailable | Falha transitória de storage ao ler um arquivo de entrada — com retry |
python_unavailable | A linguagem Python não está habilitada neste ambiente |
Dicas
- Sempre produza um resultado —
returnno JavaScript,output.jsonno Python — e mantenha-o compatível com JSON. - Use
console.log/print()enquanto constrói o passo; a saídalogsé a forma mais fácil de depurar. - Cada chamada de
fetchtambém é limitada pelo tempo do passo, então mantenha chamadas a terceiros bem dentro do orçamento de tempo. - Arquivos são o canal certo para qualquer coisa grande: o resultado é limitado a 2 MiB, enquanto arquivos carregam até 24 MiB por execução.