首页 > 解决方案 > 链接承诺以创建 ec2 实例

问题描述

我想以以前使用回调创建 ec2 实例的承诺方式重写脚本。我的逻辑是首先尝试描述安全组。如果不存在,则创建一个,否则继续描述密钥对。如果密钥对不存在,则创建一个并将私钥写入文件,否则继续创建实例。

不知何故,我设法做到了如下,但我对代码的平坦度不满意。仍然有很多缩进。此外,我发现我的逻辑迫使我将链式 Promise 嵌套在 catch 块中,这不是那些教程中人们通常这样做的方式,从而使我怀疑使用 Promise 的方式和最初目的。

var describeSecurityGroupsInstance = ec2.describeSecurityGroups(securityGroups).promise()
//1st level chain
describeSecurityGroupsInstance.then(function(data){
    console.log("SecurityGroups Already Exist")
}).catch(function(err){
    console.log("Unable to describe SecurityGroup", err)
    var createSecurityGroupInstance = ec2.createSecurityGroup(securityGroup).promise()
    //2nd level chain
    createSecurityGroupInstance.then(function(data){
        console.log("SecurityGroup test created") 
        var describeKeyPairsInstance = ec2.describeKeyPairs(keyPairs).promise()
        return describeKeyPairsInstance
    }).then(function(data){
        console.log("KeyPair Already Exist, make sure you have private key locally to proceed")
    }).catch(function(err){
        console.log("Unable to describe KeyPairs", err)
        var createKeyPairInstance = ec2.createKeyPair(keyPair).promise()
        //3rd level chain
        createKeyPairInstance.then(function(data){
            console.log("KeyPair test created")
            const writeFileInstance = util.promisify(fs.writeFile)
            privateKey=data.KeyMaterial
            return writeFileInstance('test.pem',privateKey)
        }).then(function(data){
            console.log("keypair content write to file")
            var instancePromise = ec2.runInstances(instanceParams).promise()
            return instancePromise
        }).then(function(data){
            console.log("instance just created")
            console.log(data)
        }).catch(function(err){
            console.log("Unable to create KeyPair or unable to write to file or create instance", err, err.stack)
        })
    })
})

所以现在,我有 3 级承诺链。

我的第一个问题是我能否describeKeyPairsInstance在 catch 块之后立即将承诺放入顶级链中describeSecurityGroupsInstance,因为从逻辑上讲,在与 securityGroup 检查之后,我们应该检查 KeyPairs 或相反。(IMO 这两个步骤之间的顺序无关紧要,如果我错了)。基本上我可以忍受嵌套链来解决 securityGroups 的不存在,因为它是必须的,但不是describeKeyPairsInstance一部分。如果这个目标可以实现,我认为writeFileInstance也可以附加到顶级链上,那么问题就解决了。所以问题变成了如何将承诺从二级链返回到顶级链。现在虽然我认为这不可行,但如果有解决方案,我真的很感激。

我的第二个问题是创建 ec2 实例本身的逻辑。我应该简单地摆脱describeSecurityGroups/KeyPairs这两个承诺,而不是根据createSecurityGroup/KeyPair承诺的拒绝来检查存在吗?如果是这样,那么无论 securityGroup 和 keyPair 是否存在,我都可以链接 promise。但是幂等的说,我们不应该先检查存在吗?

我的第三个问题是关于 Promise 的一般用法。将承诺链嵌套在 catch 块中是不好的做法吗?如果是这样,有或没有承诺的替代方法是什么?

回答任何问题都会有所帮助。提前致谢。

标签: javascriptnode.jsamazon-web-servicesamazon-ec2promise

解决方案


通过“反转”成功/失败逻辑,ec2.describeSecurityGroupsec2.describeKeyPairs可以“扁平化”此代码

const writeFileInstance = util.promisify(fs.writeFile);
const describeSecurityGroupsInstance () => ec2.describeSecurityGroups(securityGroups).promise()
    .then(() => { throw 'SecurityGroups Already Exist'}, err => err);
const describeKeyPairsInstance = () => ec2.describeKeyPairs(keyPairs).promise()
    .then(() => { throw 'KeyPair Already Exist, make sure you have private key locally to proceed'}, err => err);

describeSecurityGroupsInstance()
.then(res => {
    console.log("Unable to describe SecurityGroup", res);
    return ec2.createSecurityGroup(securityGroup).promise();
})
.then(describeKeyPairsInstance)
.then(res => {
    console.log("Unable to describe KeyPairs", res);
    return ec2.createKeyPair(keyPair).promise();
})
.then(data => {
    console.log("KeyPair test created");
    privateKey = data.KeyMaterial;
    return writeFileInstance('test.pem',privateKey);
})
.then(data => {
    console.log("keypair content write to file")
    return ec2.runInstances(instanceParams).promise();
})
.then(data => {
    console.log("instance just created");
    console.log(data);
})
.catch(err => {
    if (typeof err === 'string') {
        console.log(err);
    } else {
        console.log(err, err.stack);
    }
});

使用 async/await(以及反转逻辑),代码看起来更干净

const writeFileInstance = util.promisify(fs.writeFile);
const describeSecurityGroupsInstance () => ec2.describeSecurityGroups(securityGroups).promise()
    .then(() => { throw 'SecurityGroups Already Exist'}, err => err);
const describeKeyPairsInstance = () => ec2.describeKeyPairs(keyPairs).promise()
    .then(() => { throw 'KeyPair Already Exist, make sure you have private key locally to proceed'}, err => err);

try {
    const sec = await describeSecurityGroupsInstance();
    console.log("Unable to describe SecurityGroup", sec);
    await ec2.createSecurityGroup(securityGroup).promise();
    const kpi = await describeKeyPairsInstance();
    console.log("Unable to describe KeyPairs", kpi);
    const kp = await ec2.createKeyPair(keyPair).promise();
    console.log("KeyPair test created");
    privateKey = kp.KeyMaterial;
    await writeFileInstance('test.pem',privateKey);
    console.log("keypair content write to file");
    const data = await ec2.runInstances(instanceParams).promise();
    console.log("instance just created");
    console.log(data);
} catch(err) {
    if (typeof err === 'string') {
        console.log(err);
    } else {
        console.log(err, err.stack);
    }
});

推荐阅读