node.js async / await или generic-pool вызывает бесконечный цикл? - PullRequest
0 голосов
/ 14 октября 2018

Я пытался создать сценарий автоматизации для работы, он должен использовать несколько экземпляров кукловода для одновременной обработки входных строк.очередь задач и количество экземпляров кукловода контролируются универсальным пулом пакета, как ни странно, когда я запускаю сценарий в Ubuntu или Debian, кажется, что он попадает в бесконечный цикл.пытается запустить бесконечное количество экземпляров кукловода.в то время как при запуске в Windows вывод был нормальным.

const puppeteer = require('puppeteer');
const genericPool = require('generic-pool');
const faker = require('faker');
let options = require('./options');
let i = 0;
let proxies = [...options.proxy];

const pool = genericPool.createPool({
    create: async () => {
        i++;
        console.log(`create instance ${i}`);
        if (!proxies.length) {
            proxies = [...options.proxy];
        }
        let {control = null, proxy} = proxies.pop();
        let instance = await puppeteer.launch({
            headless: true,
            args: [
                `--proxy-server=${proxy}`,
            ]
        });
        instance._own = {
            proxy,
            tor: control,
            numInstance: i,
        };
        return instance;
    },
    destroy: async instance => {
        console.log('destroy instance', instance._own.numInstance);
        await instance.close()
    },
}, {
    max: 3, 
    min: 1, 
});

async function run(emails = []) {
    console.log('Processing', emails.length);
    const promises = emails.map(email => {
        console.log('Processing', email)
        pool.acquire()
            .then(browser => {
                console.log(`${email} handled`)
                pool.destroy(browser);})
    })
    await Promise.all(promises)
    await pool.drain();
    await pool.clear();
}

let emails = [a,b,c,d,e,];
run(emails)

Вывод

create instance 1
Processing 10
Processing Stacey_Haley52
Processing Polly.Block
create instance 2
Processing Shanny_Hudson59
Processing Vivianne36
Processing Jayda_Ullrich
Processing Cheyenne_Quitzon
Processing Katheryn20
Processing Jamarcus74
Processing Lenore.Osinski
Processing Hobart75
create instance 3
create instance 4
create instance 5
create instance 6
create instance 7
create instance 8
create instance 9

это из-за моих асинхронных функций?Как я могу это исправить?Благодарим Вас за помощь!

Редактировать 1. изменено в соответствии с предложенным @James

Ответы [ 2 ]

0 голосов
/ 15 октября 2018

Основная проблема, которую вы пытаетесь решить,

Предполагается использовать несколько экземпляров кукловода для одновременной обработки входных строк.

Очередь обещаний

Вы можете использовать довольно простое решение, включающее простую очередь обещаний.Мы можем использовать пакет p-queue для ограничения параллелизма по своему желанию.Я использовал это в нескольких проектах очистки, чтобы всегда тестировать вещи.

Вот как вы можете это использовать.

// emails to handle
let emails = [a, b, c, d, e, ];

// create a promise queue
const PQueue = require('p-queue');

// create queue with concurrency, ie: how many instances we want to run at once
const queue = new PQueue({
    concurrency: 1
});

// single task processor
const createInstance = async (email) => {
    let instance = await puppeteer.launch({
        headless: true,
        args: [
            `--proxy-server=${proxy}`,
        ]
    });
    instance._own = {
        proxy,
        tor: control,
        numInstance: i,
    };
    console.log('email:', email)
    return instance;
}

// add tasks to queue
for (let email of emails) {
    queue.add(async () => createInstance(email))
}

Общая проблема с бесконечным циклом пула

Я удалил всесвоего рода код, связанный с кукловодом, из вашего примера кода и видел, как он все еще генерирует бесконечный вывод на консоль.

create instance 70326
create instance 70327
create instance 70328
create instance 70329
create instance 70330
create instance 70331
...

Теперь, если вы протестируете несколько раз, вы увидите, что он будет запускать цикл, только если вычто-то в вашем коде не работает.Виновным является это pool.acquire() обещание, которое просто ставит в очередь ошибку.

Чтобы найти причину сбоя, используйте следующие события:

pool.on("factoryCreateError", function(err) {
  console.log('factoryCreateError',err);
});

pool.on("factoryDestroyError", function(err) {
  console.log('factoryDestroyError',err);
});

Есть некоторые проблемы, связанные сна это:

  • acqu () никогда не разрешает / отклоняет, если фабрика всегда отклоняет, здесь .
  • О функции получения в pool.js, здесь .
  • .acquire () не отклоняется при сбое создания ресурса, здесь .

Удачи!

0 голосов
/ 14 октября 2018

Вы хотите вернуться со своей карты, а не await, также не await в вызове destroy, возвращайте результат, и вы можете связать их, например,

const promises = emails.map(e => pool.acquire().then(pool.destroy));

Или альтернативноВы можете просто полностью избавиться от destroy, например

pool.acquire().then(b => b.close())
...