Почему строка 27 выполняется перед строкой 24?

1

Я начинаю с javascript и пытаюсь создать чистый объект для использования библиотеки Dockerode в моем примере использования. У меня проблема с асинхронностью здесь, моя строка 27 выполняется до 24, и я не понимаю, почему и как ее исправить!

Кроме того, если вам это проще, посетите эту публикацию: https://gist.github.com/msitruk/2cdb655a0bebdb29c61d8bc5606a2695

const Docker = require('dockerode');
const docker = new Docker({
    socketPath: '/var/run/docker.sock'
});

// CONSTRUCTOR
function SearchUtils() {
    this.listContainersPromise = docker.listContainers({all: true});
    this.scraperListId = [];
}

// "METHODS"
SearchUtils.prototype.run = function() {
    this.getScraperContainersListPromise()
        .then((containers) => {
            for (let i = 0; i < containers.length; i++) {
                if (containers[i].Names.toString().indexOf("scraper") !== -1) {
                    this.addToScraperList(containers[i].Id, "wait");
                }
            }
        }, (err)=>{console.log(err)})
        .then(()=>{
            this.checkReadyScraper();
        },(err)=>{console.log(err)})
        .then(() => {
            this.scrap();
        }, (err)=>{console.log(err)});
};

SearchUtils.prototype.checkReadyScraper = function() {
    for (let i = 0; i < this.scraperListId.length; i++) {
        this.exec("getStatus", this.scraperListId[i].id);
    }
};

SearchUtils.prototype.getScraperContainersListPromise = function() {
    return this.listContainersPromise; // <- Not working
};

SearchUtils.prototype.exec = function(type, containerId){
    let container = docker.getContainer(containerId);
    if (type === "getStatus"){
        this.runExec(container, 'cat /home/immobot/status');
    }
    else if (type === "scrap") {
        this.runExec(container, 'torify scrapy crawl seloger -o seloger.json');
    }
};

SearchUtils.prototype.scrap = function() {
    let localRdyScraperList = [];
    for (let i = 0; i < this.scraperListId.length; i++) {
        if(this.scraperListId[i].status.toString('utf8').indexOf("ready") !== -1){
            localRdyScraperList.push(this.scraperListId[i].id);
        }
    }
    console.log("test de localRdyScraperList : "+localRdyScraperList);
    // this.exec("scrap", this.scraperListId[i].id);
};

SearchUtils.prototype.addToScraperList = function(containerId,status) {
    this.scraperListId.push({id: containerId, status: status});
};

SearchUtils.prototype.getScraperList = function() {
    return this.scraperListId;
};

SearchUtils.prototype.getScraperList = function() {
    return this.scraperListId;
};

SearchUtils.prototype.runExec = function (container, cmd) {
    let options = {
        Cmd: [ '/bin/bash', '-c', cmd ],
        AttachStdout: true,
        AttachStderr: true
    };

    container.exec(options, (err, exec) => {
        if (err) return;
        exec.start((err, stream) => {
            if (err){
                console.log("error : "+err);
                return;
            }

            // container.modem.demuxStream(stream, process.stdout, process.stderr)

            if (cmd === "cat /home/immobot/status"){
                let newStream = require('stream');
                let logStream = new newStream.PassThrough();
                logStream.on('data', (chunk) => {
                    // console.log(chunk.toString('utf8'));
                    if (chunk.toString('utf8').indexOf("ready") !== -1){
                        console.log("CONTAINER READY !!");
                        //EDIT CONTAINER STATUS IN SCRAPERLIST TO READY
                        this.changeStatusToReady(container.id);
                    }
                });
                container.modem.demuxStream(stream, logStream, process.stderr);

            }
            else if (cmd === "torify scrapy crawl seloger -o seloger.json"){
                console.log("on lance le scrape sur un des scraper rdy");
                container.modem.demuxStream(stream, process.stdout, process.stderr)
            }

            // container.modem.demuxStream(stream, logStream, process.stderr);

            exec.inspect(function(err, data) {
                if (err){
                    console.log("error : "+err);
                    return;
                }
            });
        });
    });
};

SearchUtils.prototype.changeStatusToReady = function (containerId){
    for (let i = 0; i < this.scraperListId.length; i++) {
        if(this.scraperListId[i].id === containerId){
            this.scraperListId[i].status = "ready";
        }
    }
    // console.log(this.getScraperList());
};

module.exports = SearchUtils;
  • 0
    это container.exec синхронный или асинхронный?
  • 0
    и вы имеете в виду, если вы добавляете консольные журналы раньше в строках 24 и 27, второй называется первым?
Показать ещё 2 комментария
Теги:
ecmascript-6
docker

3 ответа

3

Если ваша цепочка обещает, не забудьте вернуться к следующему обещанию.

например..

.then(()=>{
  this.checkReadyScraper();
}

Если checkReadyScraper() является обещанием, тогда вы захотите его вернуть.

например.

.then(()=>{
  return this.checkReadyScraper();
}

В противном случае все ваши действия выполняются checkReadyScraper() и полностью игнорируют возвращенное обещание.

Вот как я думаю, что ваш runExec должен выглядеть. Я предполагаю, что exec.inspect - это то, что вы хотите разрешить.

SearchUtils.prototype.runExec = function (container, cmd) {
    return new Promise ((resolve, reject)=>{
        let options = {
            Cmd: [ '/bin/bash', '-c', cmd ],
            AttachStdout: true,
            AttachStderr: true
        };

        container.exec(options, (err, exec) => {
            if (err) return reject(err); //return error
            exec.start((err, stream) => {
                if (err){
                    console.log("error : "+err);
                    return reject(err); //return error
                }

                // container.modem.demuxStream(stream, process.stdout, process.stderr)

                if (cmd === "cat /home/immobot/status"){
                    let newStream = require('stream');
                    let logStream = new newStream.PassThrough();
                    logStream.on('data', (chunk) => {
                        // console.log(chunk.toString('utf8'));
                        if (chunk.toString('utf8').indexOf("ready") !== -1){
                            console.log("CONTAINER READY !!");
                            //EDIT CONTAINER STATUS IN SCRAPERLIST TO READY
                            this.changeStatusToReady(container.id);
                        }
                    });
                    container.modem.demuxStream(stream, logStream, process.stderr);

                }
                else if (cmd === "torify scrapy crawl seloger -o seloger.json"){
                    console.log("on lance le scrape sur un des scraper rdy");
                    container.modem.demuxStream(stream, process.stdout, process.stderr)
                }

                // container.modem.demuxStream(stream, logStream, process.stderr);

                exec.inspect(function(err, data) {
                    if (err){
                        console.log("error : "+err);
                        //don't forget to return the rejection
                        return reject(err);
                    }
                    //looks like everything was ok, lets resolve
                    resolve(data);
                });
            });
        });
        //resolve("ok"); too early
        // TODO ADD EROR STRATEGY
        //reject("error"), pointless
    });
};
  • 0
    Я пытаюсь изменить код, как этот pastebin.com/hWReW6iz, но без изменений
  • 0
    Поскольку checkReadyScraper() не является обещанием. Вам нужно убедиться, что все, что находится на линии ниже, возвращает обещание, глядя на ваш gitHub gist, ваш exec является асинхронной функцией, потому что она вызывает runExec, вам нужно превратить runExec в функция, основанная на обещаниях.
Показать ещё 4 комментария
0

Во-первых - нет необходимости обрабатывать ошибки в каждом вызове then(). Вы можете реализовать единую ошибку, которая будет ловить ошибку в любом элементе then() в последовательности:

.then(()=> {
  this.checkReadyScraper();
})
.then(() => {
  this.scrap();
})
.catch(e => console.log(e))

Также обратите внимание, что функция стрелок, подобная catch (e => console.log(e)), не требует {} и;

Ваша проблема в том, что ваша задача - Async. Если вы хотите связать задачи - вы должны сделать задачу, чтобы вернуть обещание

Это грубо говоря, что вы должны реорганизовать:

//Should return Promise
SearchUtils.prototype.exec = function(type, containerId){
  let container = docker.getContainer(containerId);
  if (type === "getStatus"){
    //runExec should return us a Promise
    return this.runExec(container, 'cat /home/immobot/status');
  }
  else if (type === "scrap") {
    return this.runExec(container, 'torify scrapy crawl seloger -o seloger.json');
  }
};

SearchUtils.prototype.runExec = function (container, cmd) {
  return new Promise(function(resolve, reject) {
     //do some stuff
     //then call resolve(result)
     //or call reject(error)
  });
}

После этого вы сможете объединить обещания (что на самом деле довольно удивительно и помогает решать обратный ад):

.then(()=> {
  //this not returns Promise, and it will be correctly chained 
  return this.checkReadyScraper();
})
.then(() => {
  //this not returns Promise, and it will be correctly chained
  return this.scrap();
})
.catch(e => console.log(e))

Кроме того, чтобы это выглядело чище, я даже рекомендую сделать небольшой рефакторинг, который, наконец, даст вам oneliner:

.then(this.checkReadyScraper).then(this.scrap).catch(console.log)
  • 0
    Большое спасибо за всю эту помощь, я пытаюсь!
  • 0
    Я пытаюсь, но всегда одно и то же .. было вонг .. chekc моя новая ревизия: gist.github.com/msitruk/2cdb655a0bebdb29c61d8bc5606a2695
0

Выполнение задачи (с контейнером.exec, в строке 81 в вашем коде) выполняется асинхронно с остальными шагами, с обратным вызовом, когда они будут выполнены. Вам нужно будет убедиться, что все проверки скребков закончены, прежде чем запускать команду утилизации, если заказ имеет значение.

  • 0
    Я думаю, что вы правы, но я не могу понять, как это, но я продолжаю расследовать на этой стороне!
  • 0
    Я пытаюсь, но всегда одно и то же .. было вонг .. chekc моя новая ревизия: gist.github.com/msitruk/2cdb655a0bebdb29c61d8bc5606a2695

Ещё вопросы

Сообщество Overcoder
Наверх
Меню