Synthetics 运行时版本 - Amazon CloudWatch
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

Synthetics 运行时版本

创建或更新金丝雀时,您可以为金丝雀选择 Synthetics 运行时版本。Synthetics 运行时是调用脚本处理程序的 Synthetics 代码,以及捆绑依赖关系的 Lambda 层的组合。

CloudWatch Synthetics 目前支持将 Node.js 用于脚本和 Puppeteer 框架的运行时,以及使用 Python 编写脚本和将 Selenium Webdriver 用于框架的运行时。

我们建议您始终为金丝雀使用最新的运行时版本,以便能够使用最新的功能和对 Synthetics 库进行的更新。

CloudWatch Synthetics 运行时支持策略

Synthetics 运行时版本受维护和安全更新的约束。如果不再支持运行时版本的任何组件,则该 Synthetics 运行时版本将被弃用。

您无法使用已弃用的运行时版本创建金丝雀。使用已弃用运行时的金丝雀将继续运行。您可以停止、启动和删除这些金丝雀。您可以通过将金丝雀更新为使用受支持的运行时版本,来更新使用已弃用运行时版本的现有金丝雀。

如果您有使用计划将在未来 60 天内弃用的运行时的金丝雀,则 CloudWatch Synthetics 会通过电子邮件通知您。我们建议您将金丝雀迁移到受支持的运行时版本,以享受最新版本中包含的新功能、安全性和性能增强的益处。

如何将金丝雀更新到新的运行时版本?

您可以使用 CloudWatch 控制台、Amazon CloudFormation、Amazon CLI 或 Amazon SDK 更新金丝雀的运行时版本。当使用 CloudWatch 控制台更新时,您可以一次最多更新五个金丝雀,方法是在金丝雀列表页面中选中它们,然后选择 Actions(操作)Update Runtime(更新运行时)

要验证升级,您可以先使用 CloudWatch 控制台克隆金丝雀,然后更新其运行时版本。这会再创建一个金丝雀,其是原始金丝雀的克隆。在使用新的运行时版本验证了金丝雀后,您便可以更新原始金丝雀的运行时版本并删除克隆金丝雀。

您还可以使用升级脚本更新多个金丝雀。有关更多信息,请参阅金丝雀运行时升级脚本

如果升级金丝雀失败,请参阅 排查失败金丝雀的问题

运行时弃用日期

运行时版本 弃用日期

syn-nodejs-puppeteer-3.4

2022 年 11 月 13 日

syn-nodejs-puppeteer-3.3

2022 年 11 月 13 日

syn-nodejs-puppeteer-3.2

2022 年 11 月 13 日

syn-nodejs-puppeteer-3.1

2022 年 11 月 13 日

syn-nodejs-puppeteer-3.0

2022 年 11 月 13 日

syn-nodejs-2.2

2021 年 5 月 28 日

syn-nodejs-2.1

2021 年 5 月 28 日

syn-nodejs-2.0

2021 年 5 月 28 日

syn-nodejs-2.0-beta

2021 年 2 月 8 日

syn-1.0

2021 年 5 月 28 日

金丝雀运行时升级脚本

若要将金丝雀脚本升级到支持的运行时版本,请使用以下脚本。

const AWS = require('aws-sdk'); // You need to configure your Amazon credentials and Region. // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html const synthetics = new AWS.Synthetics(); const DEFAULT_OPTIONS = { /** * The number of canaries to upgrade during a single run of this script. */ count: 10, /** * No canaries are upgraded unless force is specified. */ force: false }; /** * The number of milliseconds to sleep between GetCanary calls when * verifying that an update succeeded. */ const SLEEP_TIME = 5000; (async () => { try { const options = getOptions(); const versions = await getRuntimeVersions(); const canaries = await getAllCanaries(); const upgrades = canaries .filter(canary => !versions.isLatestVersion(canary.RuntimeVersion)) .map(canary => { return { Name: canary.Name, FromVersion: canary.RuntimeVersion, ToVersion: versions.getLatestVersion(canary.RuntimeVersion) }; }); if (options.force) { const promises = []; for (const upgrade of upgrades.slice(0, options.count)) { const promise = upgradeCanary(upgrade); promises.push(promise); // Sleep for 100 milliseconds to avoid throttling. await usleep(100); } const succeeded = []; const failed = []; for (let i = 0; i < upgrades.slice(0, options.count).length; i++) { const upgrade = upgrades[i]; const promise = promises[i]; try { await promise; console.log(`The update of ${upgrade.Name} succeeded.`); succeeded.push(upgrade.Name); } catch (e) { console.log(`The update of ${upgrade.Name} failed with error: ${e}`); failed.push({ Name: upgrade.Name, Reason: e }); } } if (succeeded.length) { console.group('The following canaries were upgraded successfully.'); for (const name of succeeded) { console.log(name); } console.groupEnd() } else { console.log('No canaries were upgraded successfully.'); } if (failed.length) { console.group('The following canaries were not upgraded successfully.'); for (const failure of failed) { console.log('\x1b[31m', `${failure.Name}: ${failure.Reason}`, '\x1b[0m'); } console.groupEnd(); } } else { console.log('Run with --force [--count <count>] to perform the first <count> upgrades shown. The default value of <count> is 10.') console.table(upgrades); } } catch (e) { console.error(e); } })(); function getOptions() { const force = getFlag('--force', DEFAULT_OPTIONS.force); const count = getOption('--count', DEFAULT_OPTIONS.count); return { force, count }; function getFlag(key, defaultValue) { return process.argv.includes(key) || defaultValue; } function getOption(key, defaultValue) { const index = process.argv.indexOf(key); if (index < 0) { return defaultValue; } const value = process.argv[index + 1]; if (typeof value === 'undefined' || value.startsWith('-')) { throw `The ${key} option requires a value.`; } return value; } } function getAllCanaries() { return new Promise((resolve, reject) => { const canaries = []; synthetics.describeCanaries().eachPage((err, data) => { if (err) { reject(err); } else { if (data === null) { resolve(canaries); } else { canaries.push(...data.Canaries); } } }); }); } function getRuntimeVersions() { return new Promise((resolve, reject) => { const jsVersions = []; const pythonVersions = []; synthetics.describeRuntimeVersions().eachPage((err, data) => { if (err) { reject(err); } else { if (data === null) { jsVersions.sort((a, b) => a.ReleaseDate - b.ReleaseDate); pythonVersions.sort((a, b) => a.ReleaseDate - b.ReleaseDate); resolve({ isLatestVersion(version) { const latest = this.getLatestVersion(version); return latest === version; }, getLatestVersion(version) { if (jsVersions.some(v => v.VersionName === version)) { return jsVersions[jsVersions.length - 1].VersionName; } else if (pythonVersions.some(v => v.VersionName === version)) { return pythonVersions[pythonVersions.length - 1].VersionName; } else { throw Error(`Unknown version ${version}`); } } }); } else { for (const version of data.RuntimeVersions) { if (version.VersionName === 'syn-1.0') { jsVersions.push(version); } else if (version.VersionName.startsWith('syn-nodejs-2.')) { jsVersions.push(version); } else if (version.VersionName.startsWith('syn-nodejs-puppeteer-')) { jsVersions.push(version); } else if (version.VersionName.startsWith('syn-python-selenium-')) { pythonVersions.push(version); } else { throw Error(`Unknown version ${version.VersionName}`); } } } } }); }); } async function upgradeCanary(upgrade) { console.log(`Upgrading canary ${upgrade.Name} from ${upgrade.FromVersion} to ${upgrade.ToVersion}`); await synthetics.updateCanary({ Name: upgrade.Name, RuntimeVersion: upgrade.ToVersion }).promise(); while (true) { await usleep(SLEEP_TIME); console.log(`Getting the state of canary ${upgrade.Name}`); const response = await synthetics.getCanary({ Name: upgrade.Name }).promise(); const state = response.Canary.Status.State; console.log(`The state of canary ${upgrade.Name} is ${state}`); if (state === 'ERROR' || response.Canary.Status.StateReason) { throw response.Canary.Status.StateReason; } if (state !== 'UPDATING') { return; } } } function usleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }