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

Synthetics 运行时版本

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

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

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

CloudWatch Synthetics 运行时支持策略

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

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

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

如何将 Canary 更新到新的运行时版本?

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

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

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

如果升级 Canary 失败,请参阅 排查失败 Canary 的问题

运行时弃用日期

运行时版本 弃用日期

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 日

Canary 运行时升级脚本

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

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)); }