npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

async-runner-js

v1.0.0

Published

Uma classe JavaScript robusta para execução de tarefas assíncronas em paralelo com controle de concorrência, sistema de retry, timeouts e monitoramento de progresso

Downloads

2

Readme

AsyncRunner

Uma classe JavaScript robusta para execução de tarefas assíncronas em paralelo com controle de concorrência, sistema de retry, timeouts e monitoramento de progresso.

📋 Características

  • Execução paralela com controle de concorrência
  • Sistema de retry automático com backoff exponencial
  • Timeout configurável por tarefa
  • Controle de execução (pause/resume/stop)
  • Callbacks para progresso e eventos
  • Relatórios detalhados com estatísticas
  • Gerenciamento de erros robusto
  • Retry seletivo de tarefas falhadas
  • Metadados personalizados por tarefa
  • Status tracking em tempo real

🚀 Instalação

npm install async-runner-js
// ESM
import AsyncRunner from 'async-runner-js';
import { createAsyncRunner } from 'async-runner-js';

// CommonJS
const AsyncRunner = require('async-runner-js');
const { createAsyncRunner } = require('async-runner-js');

📖 Uso Básico

Exemplo Simples

import AsyncRunner from 'async-runner-js';

// Criar uma instância
const runner = new AsyncRunner({
    concurrency: 3,      // Máximo 3 tarefas paralelas
    retryAttempts: 2,    // 2 tentativas por tarefa
    timeout: 5000        // 5 segundos de timeout
});

// Adicionar tarefas
runner
    .addTask(async () => {
        const response = await fetch('https://api.exemplo.com/dados');
        return await response.json();
    }, { id: 'buscar-dados' })
    .addTask(async () => {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return { resultado: 'processado' };
    }, { id: 'processar' });

// Executar
const report = await runner.run();
console.log('Relatório:', report);

Exemplo Avançado

const runner = new AsyncRunner({
    concurrency: 5,
    retryAttempts: 3,
    retryDelay: 1000,
    timeout: 10000,
    onProgress: (progress) => {
        console.log(`📊 Progresso: ${progress.percentage}% (${progress.completed}/${progress.total})`);
    },
    onTaskComplete: (task) => {
        console.log(`✅ Tarefa ${task.id} concluída em ${task.endTime - task.startTime}ms`);
    },
    onTaskError: (task, error) => {
        console.log(`❌ Erro na tarefa ${task.id}: ${error.message}`);
    }
});

// Adicionar várias tarefas de uma vez
const tarefas = [
    [async () => await processarPedido(1), { id: 'pedido-1', priority: 'high' }],
    [async () => await processarPedido(2), { id: 'pedido-2', priority: 'medium' }],
    [async () => await enviarEmail('[email protected]'), { id: 'email-1' }]
];

runner.addTasks(tarefas);

const report = await runner.run();

// Analisar resultados
console.log(`Total: ${report.summary.total}`);
console.log(`Sucessos: ${report.summary.successful}`);
console.log(`Falhas: ${report.summary.failed}`);
console.log(`Taxa de sucesso: ${report.summary.successRate}%`);

⚙️ Configurações

Opções do Constructor

const runner = new AsyncRunner({
    concurrency: 3,        // Número máximo de tarefas paralelas (padrão: 3)
    retryAttempts: 3,      // Número de tentativas por tarefa (padrão: 3)
    retryDelay: 1000,      // Delay entre tentativas em ms (padrão: 1000)
    timeout: 30000,        // Timeout por tarefa em ms (padrão: 30000)
    onProgress: null,      // Callback de progresso
    onTaskComplete: null,  // Callback quando tarefa completa
    onTaskError: null      // Callback quando tarefa falha
});

Callbacks Disponíveis

// Callback de progresso
onProgress: (progress) => {
    // progress = { total, completed, pending, percentage }
    console.log(`Progresso: ${progress.percentage}%`);
}

// Callback de tarefa completa
onTaskComplete: (task) => {
    // task = { id, fn, metadata, status, result, duration, ... }
    console.log(`Tarefa ${task.id} concluída`);
}

// Callback de erro
onTaskError: (task, error) => {
    console.log(`Erro na tarefa ${task.id}: ${error.message}`);
}

📝 API Reference

Métodos Principais

addTask(task, metadata = {})

Adiciona uma única tarefa ao runner.

runner.addTask(
    async () => await minhaFuncao(),
    { 
        id: 'minha-tarefa',
        priority: 'high',
        customData: 'valor personalizado'
    }
);

addTasks(tasks)

Adiciona múltiplas tarefas de uma vez.

runner.addTasks([
    async () => await tarefa1(),
    [async () => await tarefa2(), { id: 'tarefa-2' }],
    [async () => await tarefa3(), { id: 'tarefa-3', priority: 'low' }]
]);

run()

Executa todas as tarefas e retorna um relatório completo.

const report = await runner.run();

Controle de Execução

pause() / resume()

Pausa e retoma a execução.

runner.pause();   // Pausa após o lote atual
runner.resume();  // Retoma a execução

stop()

Para completamente a execução.

runner.stop();

Métodos de Consulta

getTaskById(id)

Busca uma tarefa específica pelo ID.

const task = runner.getTaskById('minha-tarefa');
console.log(task.status); // 'pending', 'running', 'completed', 'failed'

getTasksByStatus(status)

Busca tarefas por status.

const pendingTasks = runner.getTasksByStatus('pending');
const completedTasks = runner.getTasksByStatus('completed');

getFailedTasks() / getSuccessfulTasks()

Busca tarefas falhadas ou bem-sucedidas.

const failed = runner.getFailedTasks();
const successful = runner.getSuccessfulTasks();

Retry e Limpeza

retryFailedTasks()

Executa novamente apenas as tarefas que falharam.

if (report.summary.failed > 0) {
    console.log('Tentando novamente tarefas falhadas...');
    const retryReport = await runner.retryFailedTasks();
}

clear() / clearResults()

Limpa tarefas ou apenas resultados.

runner.clear();        // Remove todas as tarefas (apenas se não estiver executando)
runner.clearResults(); // Limpa apenas resultados e erros

Propriedades de Status

status

Retorna o status atual do runner.

const status = runner.status;
// { isRunning: false, isPaused: false, progress: {...}, tasksCount: 5 }

progress

Retorna o progresso atual.

const progress = runner.progress;
// { total: 10, completed: 7, percentage: 70 }

isComplete

Verifica se todas as tarefas foram processadas.

if (runner.isComplete) {
    console.log('Todas as tarefas foram processadas!');
}

📊 Estrutura do Relatório

O método run() retorna um relatório detalhado:

{
    summary: {
        total: 10,              // Total de tarefas
        successful: 8,          // Tarefas bem-sucedidas
        failed: 2,              // Tarefas falhadas
        successRate: 80,        // Taxa de sucesso em %
        totalDuration: "5432ms", // Duração total
        averageDuration: "543ms" // Duração média por tarefa
    },
    results: [
        {
            taskId: "tarefa-1",
            result: { data: "resultado" },
            duration: 1200
        }
        // ...
    ],
    errors: [
        {
            taskId: "tarefa-2",
            error: "Connection timeout",
            attempts: 3,
            duration: 5000
        }
        // ...
    ],
    tasks: [
        {
            id: "tarefa-1",
            status: "completed",
            attempts: 1,
            duration: 1200,
            metadata: { priority: "high" }
        }
        // ...
    ]
}

🔧 Exemplos Práticos

Processamento de Dados em Lote

import AsyncRunner from 'async-runner-js';

async function processarLoteDeUsuarios(usuarios) {
    const runner = new AsyncRunner({
        concurrency: 10,
        retryAttempts: 2,
        timeout: 15000,
        onProgress: (progress) => {
            console.log(`Processando usuários: ${progress.percentage}%`);
        }
    });

    // Adicionar uma tarefa para cada usuário
    usuarios.forEach(usuario => {
        runner.addTask(
            async () => {
                // Validar dados
                const dadosValidados = await validarUsuario(usuario);
                
                // Salvar no banco
                const resultado = await salvarUsuario(dadosValidados);
                
                // Enviar email de boas-vindas
                await enviarEmailBoasVindas(usuario.email);
                
                return resultado;
            },
            { 
                id: `usuario-${usuario.id}`,
                email: usuario.email,
                tipo: 'processamento-usuario'
            }
        );
    });

    const report = await runner.run();
    
    console.log(`Processamento concluído:`);
    console.log(`- Total: ${report.summary.total}`);
    console.log(`- Sucessos: ${report.summary.successful}`);
    console.log(`- Falhas: ${report.summary.failed}`);

    // Retry automático para falhas
    if (report.summary.failed > 0) {
        console.log('Tentando novamente usuários com falha...');
        const retryReport = await runner.retryFailedTasks();
        console.log(`Retry: ${retryReport.summary.successful} sucessos adicionais`);
    }

    return report;
}

Download de Arquivos

async function baixarArquivos(urls) {
    const runner = new AsyncRunner({
        concurrency: 5,
        timeout: 30000,
        onTaskComplete: (task) => {
            console.log(`✅ Download concluído: ${task.metadata.filename}`);
        },
        onTaskError: (task, error) => {
            console.log(`❌ Falha no download: ${task.metadata.filename} - ${error.message}`);
        }
    });

    urls.forEach((url, index) => {
        runner.addTask(
            async () => {
                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }
                const buffer = await response.arrayBuffer();
                
                const filename = `arquivo_${index + 1}.bin`;
                await fs.writeFile(filename, Buffer.from(buffer));
                
                return {
                    filename,
                    size: buffer.byteLength,
                    url
                };
            },
            {
                id: `download-${index + 1}`,
                filename: `arquivo_${index + 1}.bin`,
                url
            }
        );
    });

    return await runner.run();
}

Integração com APIs

async function sincronizarDados() {
    const runner = new AsyncRunner({
        concurrency: 3,
        retryAttempts: 3,
        retryDelay: 2000,
        onProgress: (progress) => {
            console.log(`Sincronização: ${progress.completed}/${progress.total}`);
        }
    });

    const endpoints = [
        { name: 'usuarios', url: '/api/usuarios' },
        { name: 'produtos', url: '/api/produtos' },
        { name: 'pedidos', url: '/api/pedidos' },
        { name: 'estoque', url: '/api/estoque' }
    ];

    endpoints.forEach(endpoint => {
        runner.addTask(
            async () => {
                // Buscar dados da API
                const response = await fetch(`https://api.exemplo.com${endpoint.url}`);
                const dados = await response.json();
                
                // Processar e salvar localmente
                const resultado = await processarDados(endpoint.name, dados);
                
                return {
                    endpoint: endpoint.name,
                    registros: dados.length,
                    processados: resultado.count
                };
            },
            {
                id: `sync-${endpoint.name}`,
                endpoint: endpoint.name,
                url: endpoint.url
            }
        );
    });

    const report = await runner.run();
    
    // Log dos resultados
    report.results.forEach(result => {
        console.log(`${result.result.endpoint}: ${result.result.processados} registros sincronizados`);
    });

    return report;
}

⚠️ Considerações Importantes

Limitações de Concorrência

  • A concorrência é controlada por lotes, não por pool de workers
  • Cada lote executa completamente antes do próximo
  • Para alta concorrência, considere ajustar o valor adequadamente

Gerenciamento de Memória

  • Resultados são mantidos em memória durante a execução
  • Para grandes volumes, considere processar em chunks menores
  • Use clearResults() periodicamente se necessário

Tratamento de Erros

  • Erros são capturados e não interrompem outras tarefas
  • O sistema de retry é automático mas configurável
  • Timeouts são tratados como erros e acionam retry

Performance

  • O overhead é mínimo para tarefas de longa duração
  • Para tarefas muito rápidas, o overhead pode ser significativo
  • Teste diferentes configurações de concorrência para seu caso

🐛 Solução de Problemas

Tarefas Não Executam

// Verifique se são funções assíncronas
runner.addTask(async () => {
    // Sua lógica aqui
});

// Não faça isso:
runner.addTask(() => {
    // Função síncrona pode não funcionar como esperado
});

Timeouts Frequentes

// Aumente o timeout para tarefas demoradas
const runner = new AsyncRunner({
    timeout: 60000  // 1 minuto
});

Muitas Falhas

// Ajuste o número de tentativas e delay
const runner = new AsyncRunner({
    retryAttempts: 5,
    retryDelay: 2000  // 2 segundos entre tentativas
});

Problemas de Memória

// Processe em lotes menores
const runner = new AsyncRunner({
    concurrency: 2  // Reduza a concorrência
});

// Limpe resultados periodicamente
runner.clearResults();

📄 Licença

Este projeto está sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.

🤝 Contribuição

Contribuições são bem-vindas! Por favor, abra uma issue ou pull request para melhorias.


AsyncRunner - Execução assíncrona simplificada e poderosa para JavaScript/Node.js