diff --git a/__tests__/e2e/ci-mac-linux.sh b/__tests__/e2e/ci-mac-linux.sh index 481ace09..3794c545 100755 --- a/__tests__/e2e/ci-mac-linux.sh +++ b/__tests__/e2e/ci-mac-linux.sh @@ -77,30 +77,38 @@ s remove -y -t ./go/s.yaml rm -rf ./go/code/target cd .. -echo "test nodejs runtime with auto ..." + +echo "test nodejs runtime with provision config mode=drain ..." cd nodejs -export fc_component_function_name=nodejs18-$(uname)-$(uname -m)-$RANDSTR +export fc_component_function_name=nodejs18-provision-drain-$(uname)-$(uname -m)-$RANDSTR +s deploy -y -t s_provision_drain.yaml +s invoke -e '{"hello":"fc nodejs provision config mode=drain"}' -t s_provision_drain.yaml +s info -y -t s_provision_drain.yaml +s remove -y -t s_provision_drain.yaml + +echo "test nodejs runtime with auto ..." +export fc_component_function_name=nodejs18-nas-auto-$(uname)-$(uname -m)-$RANDSTR s deploy -y -t s_auto.yaml s invoke -e '{"hello":"fc nodejs with auto"}' -t s_auto.yaml s info -y -t s_auto.yaml s remove -y -t s_auto.yaml echo "test nodejs runtime with oss config auto ..." -export fc_component_function_name=nodejs18-$(uname)-$(uname -m)-$RANDSTR +export fc_component_function_name=nodejs18-oss-auto-$(uname)-$(uname -m)-$RANDSTR s deploy -y -t ./s_oss_config_auto.yaml s invoke -e '{"hello":"fc nodejs with oss config auto"}' -t ./s_oss_config_auto.yaml s info -y -t ./s_oss_config_auto.yaml s remove -y -t ./s_oss_config_auto.yaml echo "test nodejs runtime with more vpc and nas auto ..." -export fc_component_function_name=nodejs16-$(uname)-$(uname -m)-$RANDSTR +export fc_component_function_name=nodejs16-multi-nas-auto-$(uname)-$(uname -m)-$RANDSTR s deploy -y -t ./s_lock_auto.yaml s invoke -e '{"hello":"fc nodejs with more vpc and nas auto"}' -t ./s_lock_auto.yaml s info -y -t ./s_lock_auto.yaml s remove -y -t ./s_lock_auto.yaml echo "test nodejs runtime with tags ..." -export fc_component_function_name=nodejs16-$(uname)-$(uname -m)-$RANDSTR +export fc_component_function_name=nodejs16-tags-$(uname)-$(uname -m)-$RANDSTR s deploy -y -t ./s_tags.yaml s deploy -y -t ./s_tags2.yaml s deploy -y -t ./s_tags3.yaml diff --git a/__tests__/e2e/nodejs/hello-code/index.js b/__tests__/e2e/nodejs/hello-code/index.js new file mode 100644 index 00000000..8db8c28b --- /dev/null +++ b/__tests__/e2e/nodejs/hello-code/index.js @@ -0,0 +1,4 @@ +exports.handler = async function (event, context) { + console.log('event: \n' + event); + return 'Hello World!'; +}; diff --git a/__tests__/e2e/nodejs/s_provision_drain.yaml b/__tests__/e2e/nodejs/s_provision_drain.yaml new file mode 100644 index 00000000..9f67223f --- /dev/null +++ b/__tests__/e2e/nodejs/s_provision_drain.yaml @@ -0,0 +1,22 @@ +edition: 3.0.0 +name: test-node-app +access: quanxi + +vars: + region: ${env('REGION', 'cn-hongkong')} + +resources: + fcDemo: # 业务名称/模块名称 + component: ${env('fc_component_version', path('../../../'))} + props: # 组件的属性值 + region: ${vars.region} + functionName: fc3-event-test-drain-${env('fc_component_function_name', 'nodejs18')} + runtime: ${env('fc_component_runtime', 'nodejs18')} + code: ./hello-code + handler: index.handler + memorySize: 128 + timeout: 60 + + provisionConfig: + defaultTarget: 0 + mode: drain \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 392eaa0f..976a9fde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,9 @@ "dependencies": { "@alicloud/devs20230714": "^2.4.6-alpha.2", "@alicloud/fc2": "^2.6.6", - "@alicloud/fc20230330": "4.6.0", + "@alicloud/fc20230330": "4.6.2", "@alicloud/pop-core": "^1.8.0", - "@serverless-cd/srm-aliyun-oss": "^0.0.1-beta.4", + "@serverless-cd/srm-aliyun-oss": "^0.0.1-beta.6", "@serverless-cd/srm-aliyun-pop-core": "^0.0.8-beta.1", "@serverless-cd/srm-aliyun-ram20150501": "^0.0.2-beta.9", "@serverless-cd/srm-aliyun-sls20201230": "0.0.5-beta.3", @@ -56,7 +56,7 @@ "patch-package": "^8.0.0", "postinstall-prepare": "^2.0.0", "prettier": "^3.6.2", - "ts-jest": "^29.4.4", + "ts-jest": "^29.4.5", "ts-node": "^10.9.2", "typescript": "^4.4.2", "typescript-json-schema": "^0.65.1" @@ -213,10 +213,9 @@ } }, "node_modules/@alicloud/fc20230330": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/@alicloud/fc20230330/-/fc20230330-4.6.0.tgz", - "integrity": "sha512-9NzHBzl6lE3F2dSz1vXdx++JVuqkpZKjnUcKtzeVM3Hsbm+1Wre0YWrPQVRoKIy915NXiFDZffxClLI6a3+iEg==", - "license": "Apache-2.0", + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/@alicloud/fc20230330/-/fc20230330-4.6.2.tgz", + "integrity": "sha512-wrh8JK88CrM0t00GXW/hWkVBoLX2ReOM7nf8Hem6gaWeoB9SE9XX5j/eV7lBpmb7AwzCj8Tc5nXBNpByZhSGlw==", "dependencies": { "@alicloud/openapi-core": "^1.0.0", "@darabonba/typescript": "^1.0.0" @@ -2656,9 +2655,9 @@ "license": "ISC" }, "node_modules/@serverless-cd/srm-aliyun-oss": { - "version": "0.0.1-beta.4", - "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/@serverless-cd/srm-aliyun-oss/-/@serverless-cd/srm-aliyun-oss-0.0.1-beta.4.tgz", - "integrity": "sha512-anUa636a6B8FqA+72t7hdV82loHSfuIEFaOvQj2qrCvv458bQCrSdo7V/yk8fwVeahdYSPHhCNInnzju23TPPw==", + "version": "0.0.1-beta.6", + "resolved": "https://registry.npmmirror.com/@serverless-cd/srm-aliyun-oss/-/srm-aliyun-oss-0.0.1-beta.6.tgz", + "integrity": "sha512-PZVCCuvaBtdP8svxMF4NCRgNmhQt8Dz1jkiBiHqN4ChwOxskdeFVc0azogrgrUkWmteQV2pcTtX7SnTiCgE0SQ==", "dependencies": { "@alicloud/openapi-client": "^0.4.4", "@alicloud/openapi-util": "^0.3.1", @@ -13410,10 +13409,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", + "version": "7.7.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "bin": { "semver": "bin/semver.js" }, @@ -14535,11 +14533,10 @@ } }, "node_modules/ts-jest": { - "version": "29.4.4", - "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.4.4.tgz", - "integrity": "sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==", + "version": "29.4.5", + "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", "dev": true, - "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", "fast-json-stable-stringify": "^2.1.0", @@ -14547,7 +14544,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.7.2", + "semver": "^7.7.3", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, @@ -16168,9 +16165,9 @@ } }, "@alicloud/fc20230330": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/@alicloud/fc20230330/-/fc20230330-4.6.0.tgz", - "integrity": "sha512-9NzHBzl6lE3F2dSz1vXdx++JVuqkpZKjnUcKtzeVM3Hsbm+1Wre0YWrPQVRoKIy915NXiFDZffxClLI6a3+iEg==", + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/@alicloud/fc20230330/-/fc20230330-4.6.2.tgz", + "integrity": "sha512-wrh8JK88CrM0t00GXW/hWkVBoLX2ReOM7nf8Hem6gaWeoB9SE9XX5j/eV7lBpmb7AwzCj8Tc5nXBNpByZhSGlw==", "requires": { "@alicloud/openapi-core": "^1.0.0", "@darabonba/typescript": "^1.0.0" @@ -17973,9 +17970,9 @@ "integrity": "sha512-7JEwVh8LaXvXyN4qMfUm4PASx+kAruO4euGt6cMiLIm1Z+E3pXDPTOajqG6g87PRWVe9iW93EwE3YdIblt/S2Q==" }, "@serverless-cd/srm-aliyun-oss": { - "version": "0.0.1-beta.4", - "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/@serverless-cd/srm-aliyun-oss/-/@serverless-cd/srm-aliyun-oss-0.0.1-beta.4.tgz", - "integrity": "sha512-anUa636a6B8FqA+72t7hdV82loHSfuIEFaOvQj2qrCvv458bQCrSdo7V/yk8fwVeahdYSPHhCNInnzju23TPPw==", + "version": "0.0.1-beta.6", + "resolved": "https://registry.npmmirror.com/@serverless-cd/srm-aliyun-oss/-/srm-aliyun-oss-0.0.1-beta.6.tgz", + "integrity": "sha512-PZVCCuvaBtdP8svxMF4NCRgNmhQt8Dz1jkiBiHqN4ChwOxskdeFVc0azogrgrUkWmteQV2pcTtX7SnTiCgE0SQ==", "requires": { "@alicloud/openapi-client": "^0.4.4", "@alicloud/openapi-util": "^0.3.1", @@ -25464,9 +25461,9 @@ } }, "semver": { - "version": "7.7.2", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==" + "version": "7.7.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==" }, "semver-compare": { "version": "1.0.0", @@ -26286,9 +26283,9 @@ "dev": true }, "ts-jest": { - "version": "29.4.4", - "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.4.4.tgz", - "integrity": "sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==", + "version": "29.4.5", + "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", "dev": true, "requires": { "bs-logger": "^0.2.6", @@ -26297,7 +26294,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.7.2", + "semver": "^7.7.3", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, diff --git a/package.json b/package.json index 46857515..b2d2bf11 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "dependencies": { "@alicloud/devs20230714": "^2.4.6-alpha.2", "@alicloud/fc2": "^2.6.6", - "@alicloud/fc20230330": "4.6.0", + "@alicloud/fc20230330": "4.6.2", "@alicloud/pop-core": "^1.8.0", "@serverless-cd/srm-aliyun-pop-core": "^0.0.8-beta.1", "@serverless-cd/srm-aliyun-ram20150501": "^0.0.2-beta.9", @@ -68,7 +68,7 @@ "patch-package": "^8.0.0", "postinstall-prepare": "^2.0.0", "prettier": "^3.6.2", - "ts-jest": "^29.4.4", + "ts-jest": "^29.4.5", "ts-node": "^10.9.2", "typescript": "^4.4.2", "typescript-json-schema": "^0.65.1" diff --git a/src/resources/fc/impl/client.ts b/src/resources/fc/impl/client.ts index 1775bb82..0c283e74 100644 --- a/src/resources/fc/impl/client.ts +++ b/src/resources/fc/impl/client.ts @@ -48,6 +48,7 @@ import FCClient, { PutScalingConfigInput, GetScalingConfigRequest, DeleteScalingConfigRequest, + DisableFunctionInvocationRequest, } from '@alicloud/fc20230330'; import { ICredentials } from '@serverless-devs/component-interface'; import { RuntimeOptions } from '@alicloud/tea-util'; @@ -639,4 +640,25 @@ export default class FC_Client { ); return body; } + + async disableFunctionInvocation( + functionName: string, + abortOngoingRequest: boolean, + reason: string, + ) { + const request = new DisableFunctionInvocationRequest({ + reason, + abortOngoingRequest, + }); + const result = await this.fc20230330Client.disableFunctionInvocation(functionName, request); + const { body } = result.toMap(); + logger.debug(`DisableFunction ${functionName} result body: ${JSON.stringify(body)}`); + return body; + } + async enableFunctionInvocation(functionName: string) { + const result = await this.fc20230330Client.enableFunctionInvocation(functionName); + const { body } = result.toMap(); + logger.debug(`EnableFunction ${functionName} result body: ${JSON.stringify(body)}`); + return body; + } } diff --git a/src/resources/fc/index.ts b/src/resources/fc/index.ts index dcd915b0..86bbf063 100644 --- a/src/resources/fc/index.ts +++ b/src/resources/fc/index.ts @@ -493,6 +493,10 @@ export default class FC extends FC_Client { _.unset(body, 'ossMountConfig'); } + if (_.isEmpty(body.polarFsConfig?.mountPoints)) { + _.unset(body, 'polarFsConfig'); + } + if (_.isEmpty(body.tracingConfig)) { _.unset(body, 'tracingConfig'); } diff --git a/src/subCommands/deploy/impl/provision_config.ts b/src/subCommands/deploy/impl/provision_config.ts index 399d90e6..f7e89811 100644 --- a/src/subCommands/deploy/impl/provision_config.ts +++ b/src/subCommands/deploy/impl/provision_config.ts @@ -48,7 +48,7 @@ export default class ProvisionConfig extends Base { if (this.needDeploy) { await this.fcSdk.putFunctionProvisionConfig(this.functionName, qualifier, localConfig); - if (this.ProvisionMode === 'sync') { + if (this.ProvisionMode === 'sync' || this.ProvisionMode === 'drain') { await this.waitForProvisionReady(qualifier, localConfig); } else { logger.info( @@ -86,7 +86,16 @@ export default class ProvisionConfig extends Base { // 如果没有目标值或目标值为0,则无需等待 if (!realTarget || realTarget <= 0) { - return; + if (this.ProvisionMode !== 'drain') { + return; + } else { + logger.info(`disableFunctionInvocation ${this.functionName} ...`); + await this.fcSdk.disableFunctionInvocation(this.functionName, true, 'Fast scale-to-zero'); + await sleep(5); + logger.info(`enableFunctionInvocation ${this.functionName} ...`); + await this.fcSdk.enableFunctionInvocation(this.functionName); + return; + } } let getCurrentErrorCount = 0; @@ -143,7 +152,6 @@ export default class ProvisionConfig extends Base { // eslint-disable-next-line no-await-in-loop await sleep(5); } - logger.warn( `Timeout waiting for provisionConfig of ${this.functionName}/${qualifier} to be ready`, );