Как ведет себя child_process в Nodejs - PullRequest
0 голосов
/ 08 апреля 2019

У меня есть рабочий код Nodejs, однако библиотека child_process ведет себя странно, мне просто интересно, как эта библиотека работает.

Мой код пытается загрузить сертификаты SSL с S3, а затем создать два новых файла на основе существующих с помощью библиотеки child_process.

const AWS = require('aws-sdk');
const fs = require('fs');
const child_process = require("child_process");
const exec = require('child_process').exec; 

var s3 = new AWS.S3();

var filePath = '../Desktop/Certs/'
var bucketName = 'neb.certificates' //replace example bucket with your s3 bucket name

var params = {
    Bucket: bucketName, 
    Prefix: 'dev/jenkins.secure.care/',
  };

  s3.listObjectsV2(params, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else {
        // console.log(data.Contents)
        var len = data.Contents.length

        for(var i=0; i<len; i++){
            var key = data.Contents[i]["Key"]

            var newPath = filePath.concat(key.substring(31))

            const downloadFile = (newPath, bucketName, key) => {

                //construct getParam
                var getParams = {
                    Bucket: bucketName,
                    Key: key
                };

                s3.getObject(getParams, (err, data) => {
                    if (err) console.error(err)
                    fs.writeFileSync(newPath, data.Body.toString())
                    // console.log(`${newPath} has been created!`)
                })
            }

            downloadFile(newPath, bucketName, key)
        }
    }
  });

  exec('mv  ../Desktop/Certs/cert.pem ../Desktop/Certs/jenkins.crt', (err, stdout, stderr) => {  
    if (err) {  
      console.error(err);  
      return;  
    }  
    console.log(stdout);  
  }); 

  exec('mv ../Desktop/Certs/privkey.pem ../Desktop/Certs/jenkins.key', (err, stdout, stderr) => {  
    if (err) {  
      console.error(err);  
      return;  
    }  
    console.log(stdout);  
  }); 

Поэтому, когда я запускаю код в первый раз, он только загружает сертификаты из S3 в локальную папку, но не создает другие 2 файла. Затем я должен запустить его во второй раз, чтобы создать дополнительные файлы.

Тем не менее, я просто хочу запустить его один раз, и он имеет все, что я ожидаю.

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

child_process.execSync("sleep 5");

Пожалуйста, помогите

1 Ответ

1 голос
/ 08 апреля 2019

Похоже, проблема здесь в асинхронном выполнении вашего кода. В этом примере вот что происходит:

  1. Выполнить s3.listObjectsV2() и после завершения , обратный вызов огня (но не сейчас, в будущем )
  2. Выполнить сначала exec() и по окончании , перезвонить (но не сейчас, в будущем )
  3. Выполнение секунд exec() и по окончании , обратный вызов (но не сейчас, в будущем )

И эти три шага запускаются немедленно, один за другим. И у каждого из них есть свой собственный обратный вызов, который запускает в будущем . Хорошо, но когда будущее ? - именно так! Вы не знаете В вашем случае, вероятно, эти два обратных вызова в exec() запускаются до обратного вызова из s3, и именно поэтому он не работает.

Решение здесь состоит в том, чтобы убедиться, что эти exec() запущены после s3.listObjects. Таким образом, у вас есть два варианта: сначала сделать обещание из s3, например: s3.listObjectsV2(params).promise() и await для него, затем в .then((data) => {}) у вас есть data и в .catch((error) => {}) ваш error. Или вы можете просто поместить эти exec() в обратный вызов s3.


Ваш код должен выглядеть следующим образом согласно решению 2 (из комментариев):

const AWS = require('aws-sdk');
const fs = require('fs');
const child_process = require("child_process");
const exec = require('child_process').exec; 

var s3 = new AWS.S3();

var filePath = '../Desktop/Certs/'
var bucketName = 'neb.certificates' //replace example bucket with your s3 bucket name

var params = {
  Bucket: bucketName, 
  Prefix: 'dev/jenkins.secure.care/',
};

s3.listObjectsV2(params, async function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else {
      // console.log(data.Contents)
      var len = data.Contents.length

      for(var i=0; i<len; i++){
          var key = data.Contents[i]["Key"]

          var newPath = filePath.concat(key.substring(31))

          const downloadFile = (newPath, bucketName, key) => {

              //construct getParam
              var getParams = {
                  Bucket: bucketName,
                  Key: key
              };
              return s3.getObject(getParams).promise();
          };

          const downloadData = await downloadFile(newPath, bucketName, key).catch(console.error);
          fs.writeFileSync(newPath, downloadData.Body.toString());
          console.log(newPath, 'created');
      }

      //rename files
      console.log('renaming first cert.pem');
      exec('mv  ../Desktop/Certs/cert.pem ../Desktop/Certs/jenkins.crt', (err, stdout, stderr) => {  
        if (err) {  
          console.error(err);  
          return;  
        }  
        console.log(stdout);  
      }); 

      console.log('renaming second privkey.pem');
      exec('mv ../Desktop/Certs/privkey.pem ../Desktop/Certs/jenkins.key', (err, stdout, stderr) => {  
        if (err) {  
          console.error(err);  
          return;  
        }  
        console.log(stdout);  
      });
  }
});
...