Skip to content

Commit 47522b4

Browse files
committed
feat: support scf publish version and traffic setup
1 parent 2869a95 commit 47522b4

File tree

6 files changed

+110
-63
lines changed

6 files changed

+110
-63
lines changed

docs/configure.md

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ inputs:
3030
layers:
3131
- name: layerName # layer名称
3232
version: 1 # 版本
33+
traffic: 0.9 # 配置默认流量中 $LATEST 版本比重:0 - 1
3334
functionConf: # 函数配置相关
3435
timeout: 10 # 超时时间,单位秒
3536
memorySize: 128 # 内存大小,单位MB
@@ -40,6 +41,7 @@ inputs:
4041
vpcId: '' # 私有网络的Id
4142
subnetId: '' # 子网ID
4243
apigatewayConf: # api网关配置
44+
isDisabled: false # 是否禁用自动创建 API 网关功能
4345
enableCORS: true # 允许跨域
4446
customDomains: # 自定义域名绑定
4547
- domain: abc.com # 待绑定的自定义的域名
@@ -55,13 +57,13 @@ inputs:
5557
- http
5658
- https
5759
environment: test
60+
serviceTimeout: 15
5861
usagePlan: # 用户使用计划
5962
usagePlanId: 1111
6063
usagePlanName: slscmp
6164
usagePlanDesc: sls create
6265
maxRequestNum: 1000
6366
auth: # 密钥
64-
serviceTimeout: 15
6567
secretName: secret
6668
secretIds:
6769
- xxx
@@ -71,21 +73,20 @@ inputs:
7173
7274
主要的参数
7375
74-
| 参数名称 | 是否必选 | 默认值 | 描述 |
75-
| ---------------------------------------- | :------: | :-------------: | :------------------------------------------------------------------ |
76-
| runtime | 否 | Nodejs10.15 | 执行环境, 目前支持: Nodejs6.10, Nodejs8.9, Nodejs10.15, Nodejs12.16 |
77-
| region | 否 | ap-guangzhou | 项目部署所在区域,默认广州区 |
78-
| functionName | 否 | | 云函数名称 |
79-
| serviceName | 否 | | API 网关服务名称, 默认创建一个新的服务名称 |
80-
| serviceId | 否 | | API 网关服务 ID,如果存在将使用这个 API 网关服务 |
81-
| src | 否 | `process.cwd()` | 默认为当前目录, 如果是对象, 配置参数参考 [执行目录](#src-object) |
82-
| layers | 否 | | 云函数绑定的 layer, 配置参数参考 [层配置](#layer) |
83-
| exclude | 否 | | 不包含的文件 |
84-
| include | 否 | | 包含的文件, 如果是相对路径,是相对于 `serverless.yml`的路径 |
85-
| [functionConf](#funtionConf) | 否 | | 函数配置 |
86-
| [apigatewayConf](#apigatewayConf) | 否 | | API 网关配置 |
87-
| [cloudDNSConf](#cloudDNSConf) | 否 | | DNS 配置 |
88-
| [Region special config](#apigatewayConf) | 否 | | 指定区配置 |
76+
| 参数名称 | 是否必选 | 默认值 | 描述 |
77+
| ------------------------------------ | :------: | :-------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
78+
| runtime | 否 | Nodejs10.15 | 执行环境, 目前支持: Nodejs6.10, Nodejs8.9, Nodejs10.15, Nodejs12.16 |
79+
| region | 否 | ap-guangzhou | 项目部署所在区域,默认广州区 |
80+
| functionName | 否 | | 云函数名称 |
81+
| serviceName | 否 | | API 网关服务名称, 默认创建一个新的服务名称 |
82+
| serviceId | 否 | | API 网关服务 ID,如果存在将使用这个 API 网关服务 |
83+
| src | 否 | `process.cwd()` | 默认为当前目录, 如果是对象, 配置参数参考 [执行目录](#执行目录) |
84+
| layers | 否 | | 云函数绑定的 layer, 配置参数参考 [层配置](#层配置) |
85+
| traffic | 否 | 1 | 配置默认流量中 `$LATEST` 版本比重,取值范围:0 ~ 1,比如 80%,可配置成 0.8。注意如果配置灰度流量,需要配置对应的 API 网关触发器的 endpoints 的 `function.functionQualifier` 参数为 `$DEFAULT` (默认流量) |
86+
| [functionConf](#函数配置) | 否 | | 函数配置 |
87+
| [apigatewayConf](#API-网关配置) | 否 | | API 网关配置 |
88+
| [cloudDNSConf](#DNS-配置) | 否 | | DNS 配置 |
89+
| [Region special config](#指定区配置) | 否 | | 指定区配置 |
8990

9091
## 执行目录
9192

@@ -114,11 +115,11 @@ inputs:
114115

115116
### 指定区配置
116117

117-
| 参数名称 | 是否必选 | 类型 | 默认值 | 函数 |
118-
| --------------------------------- | :------: | ------ | ------ | ------------ |
119-
| [functionConf](#funtionConf) | 否 | Object | | 函数配置 |
120-
| [apigatewayConf](#apigatewayConf) | 否 | Object | | API 网关配置 |
121-
| [cloudDNSConf](#cloudDNSConf) | 否 | Object | | DNS 配置 |
118+
| 参数名称 | 是否必选 | 类型 | 默认值 | 函数 |
119+
| ------------------------------- | :------: | ------ | ------ | ------------ |
120+
| [functionConf](#函数配置) | 否 | Object | | 函数配置 |
121+
| [apigatewayConf](#API-网关配置) | 否 | Object | | API 网关配置 |
122+
| [cloudDNSConf](#DNS-配置) | 否 | Object | | DNS 配置 |
122123

123124
### 函数配置
124125

@@ -128,8 +129,8 @@ inputs:
128129
| ----------- | :------: | :----: | :----: | :------------------------------------------------------------------------------ |
129130
| timeout | 否 | Number | 3 | 函数最长执行时间,单位为秒,可选值范围 1-900 秒,默认为 3 秒 |
130131
| memorySize | 否 | Number | 128 | 函数运行时内存大小,默认为 128M,可选范围 64、128MB-3072MB,并且以 128MB 为阶梯 |
131-
| environment | 否 | Object | | 函数的环境变量, 参考 [环境变量](#environment) |
132-
| vpcConfig | 否 | Object | | 函数的 VPC 配置, 参考 [VPC 配置](#vpcConfig) |
132+
| environment | 否 | Object | | 函数的环境变量, 参考 [环境变量](#环境变量) |
133+
| vpcConfig | 否 | Object | | 函数的 VPC 配置, 参考 [VPC 配置](#VPC-配置) |
133134

134135
##### 环境变量
135136

@@ -146,17 +147,18 @@ inputs:
146147

147148
### API 网关配置
148149

149-
| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 |
150-
| ------------ | :------: | :------- | :------- | :--------------------------------------------------------------------------------- |
151-
| protocols | 否 | String[] | ['http'] | 前端请求的类型,如 http,https,http 与 https |
152-
| environment | 否 | String | release | 发布环境. 目前支持三种发布环境: test(测试), prepub(预发布) 与 release(发布). |
153-
| usagePlan | 否 | | | 使用计划配置, 参考 [使用计划](#usagePlan) |
154-
| auth | 否 | | | API 密钥配置, 参考 [API 密钥](#auth) |
155-
| customDomain | 否 | Object[] | | 自定义 API 域名配置, 参考 [自定义域名](#customDomain) |
156-
| isDisabled | 否 | Boolean | false | 关闭自动创建 API 网关功能。默认值为否,即默认自动创建 API 网关。 |
157-
| enableCORS | 否 | Boolean | false | 开启跨域。默认值为否。 |
150+
| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 |
151+
| -------------- | :------: | :------- | :------- | :--------------------------------------------------------------------------------- |
152+
| protocols | 否 | String[] | ['http'] | 前端请求的类型,如 http,https,http 与 https |
153+
| environment | 否 | String | release | 发布环境. 目前支持三种发布环境: test(测试), prepub(预发布) 与 release(发布). |
154+
| usagePlan | 否 | | | 使用计划配置, 参考 [使用计划](#使用计划) |
155+
| auth | 否 | | | API 密钥配置, 参考 [API 密钥](#API-密钥配置) |
156+
| customDomain | 否 | Object[] | | 自定义 API 域名配置, 参考 [自定义域名](#自定义域名) |
157+
| enableCORS | 否 | Boolean | `false` | 开启跨域。默认值为否。 |
158+
| serviceTimeout | 否 | Number | `15` | Api 超时时间,单位: 秒 |
159+
| isDisabled | 否 | Boolean | `false` | 关闭自动创建 API 网关功能。默认值为否,即默认自动创建 API 网关。 |
158160

159-
- 使用计划
161+
##### 使用计划
160162

161163
参考: https://cloud.tencent.com/document/product/628/14947
162164

@@ -167,7 +169,7 @@ inputs:
167169
| usagePlanDesc | 否 | String | 用户自定义的使用计划描述 |
168170
| maxRequestNum | 否 | Int | 请求配额总数,如果为空,将使用-1 作为默认值,表示不开启 |
169171

170-
- API 密钥配置
172+
##### API 密钥配置
171173

172174
参考: https://cloud.tencent.com/document/product/628/14916
173175

example/serverless.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
org: orgDemo # (optional) serverless dashboard org. default is the first org you created during signup.
22
app: appDemo # (optional) serverless dashboard app. default is the same as the name property.
33
stage: dev # (optional) serverless dashboard stage. default is dev.
4-
component: koa # (required) name of the component. In that case, it's koa.
4+
component: koa@dev # (required) name of the component. In that case, it's koa.
55
name: koaDemo # (required) name of your koa component instance.
66

77
inputs:
@@ -11,6 +11,7 @@ inputs:
1111
- .env
1212
region: ap-guangzhou
1313
runtime: Nodejs10.15
14+
traffic: 0.8
1415
apigatewayConf:
1516
protocols:
1617
- http

serverless.component.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: Tencent Cloud, Inc.
44
org: Tencent Cloud, Inc.
55
description: Deploys a serverless Koa.js application onto Tencent SCF and Tencent APIGateway.
66
keywords: tencent, serverless, koa
7-
repo: https://github.com/serverless-components/tencent-koa/tree/v2
8-
readme: https://github.com/serverless-components/tencent-koa/tree/v2/README.md
7+
repo: https://github.com/serverless-components/tencent-koa/
8+
readme: https://github.com/serverless-components/tencent-koa/tree/master/README.md
99
license: MIT
1010
main: ./src

src/package.json

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
11
{
2-
"name": "@serverless/koa",
3-
"main": "./serverless.js",
4-
"publishConfig": {
5-
"access": "public"
6-
},
7-
"scripts": {
8-
"test": "echo \"Error: no test specified\" && exit 1",
9-
"lint": "eslint . --fix --cache"
10-
},
11-
"author": "Tencent Cloud, Inc.",
12-
"license": "MIT",
132
"dependencies": {
143
"download": "^8.0.0",
15-
"tencent-component-toolkit": "^1.11.4",
4+
"tencent-component-toolkit": "^1.12.8",
165
"type": "^2.0.0"
176
}
187
}

src/serverless.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,26 @@ class ServerlessComponent extends Component {
5151
...(this.state[curRegion] ? this.state[curRegion] : {}),
5252
...outputs[curRegion]
5353
}
54+
55+
// default version is $LATEST
56+
outputs[curRegion].lastVersion = scfOutput.LastVersion
57+
? scfOutput.LastVersion
58+
: this.state.lastVersion || '$LATEST'
59+
60+
// default traffic is 1.0, it can also be 0, so we should compare to undefined
61+
outputs[curRegion].traffic = scfOutput.Traffic
62+
? scfOutput.Traffic
63+
: this.state.traffic !== undefined
64+
? this.state.traffic
65+
: 1
66+
67+
if (outputs[curRegion].traffic !== 1 && scfOutput.ConfigTrafficVersion) {
68+
outputs[curRegion].configTrafficVersion = scfOutput.ConfigTrafficVersion
69+
this.state.configTrafficVersion = scfOutput.ConfigTrafficVersion
70+
}
71+
72+
this.state.lastVersion = outputs[curRegion].lastVersion
73+
this.state.traffic = outputs[curRegion].traffic
5474
}
5575
uploadCodeHandler.push(funcDeployer())
5676
}

src/utils.js

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@ const ensureObject = require('type/object/ensure')
44
const ensureIterable = require('type/iterable/ensure')
55
const ensureString = require('type/string/ensure')
66
const download = require('download')
7+
const { TypeError } = require('tencent-component-toolkit/src/utils/error')
78
const CONFIGS = require('./config')
89

9-
/*
10-
* Pauses execution for the provided miliseconds
11-
*
12-
* @param ${number} wait - number of miliseconds to wait
13-
*/
14-
const sleep = async (wait) => new Promise((resolve) => setTimeout(() => resolve(), wait))
15-
1610
/*
1711
* Generates a random id
1812
*/
@@ -21,6 +15,26 @@ const generateId = () =>
2115
.toString(36)
2216
.substring(6)
2317

18+
const getType = (obj) => {
19+
return Object.prototype.toString.call(obj).slice(8, -1)
20+
}
21+
22+
const validateTraffic = (num) => {
23+
if (getType(num) !== 'Number') {
24+
throw new TypeError(
25+
`PARAMETER_${CONFIGS.compName.toUpperCase()}_TRAFFIC`,
26+
'traffic must be a number'
27+
)
28+
}
29+
if (num < 0 || num > 1) {
30+
throw new TypeError(
31+
`PARAMETER_${CONFIGS.compName.toUpperCase()}_TRAFFIC`,
32+
'traffic must be a number between 0 and 1'
33+
)
34+
}
35+
return true
36+
}
37+
2438
const getCodeZipPath = async (instance, inputs) => {
2539
console.log(`Packaging ${CONFIGS.compFullname} application...`)
2640

@@ -32,9 +46,16 @@ const getCodeZipPath = async (instance, inputs) => {
3246
const filename = 'template'
3347

3448
console.log(`Installing Default ${CONFIGS.compFullname} App...`)
35-
await download(CONFIGS.templateUrl, downloadPath, {
36-
filename: `${filename}.zip`
37-
})
49+
try {
50+
await download(CONFIGS.templateUrl, downloadPath, {
51+
filename: `${filename}.zip`
52+
})
53+
} catch (e) {
54+
throw new TypeError(
55+
`DOWNLOAD_${CONFIGS.compName.toUpperCase()}_TEMPLATE`,
56+
'Download default template failed.'
57+
)
58+
}
3859
zipPath = `${downloadPath}/${filename}.zip`
3960
} else {
4061
zipPath = inputs.code.src
@@ -199,6 +220,9 @@ const prepareInputs = async (instance, credentials, inputs = {}) => {
199220
stateFunctionName ||
200221
`${CONFIGS.compName}_component_${generateId()}`,
201222
region: regionList,
223+
role: ensureString(tempFunctionConf.role ? tempFunctionConf.role : inputs.role, {
224+
default: ''
225+
}),
202226
handler: ensureString(tempFunctionConf.handler ? tempFunctionConf.handler : inputs.handler, {
203227
default: CONFIGS.handler
204228
}),
@@ -218,8 +242,18 @@ const prepareInputs = async (instance, credentials, inputs = {}) => {
218242
fromClientRemark,
219243
layers: ensureIterable(tempFunctionConf.layers ? tempFunctionConf.layers : inputs.layers, {
220244
default: []
221-
})
245+
}),
246+
publish: inputs.publish,
247+
traffic: inputs.traffic,
248+
lastVersion: instance.state.lastVersion
249+
}
250+
251+
// validate traffic
252+
if (inputs.traffic !== undefined) {
253+
validateTraffic(inputs.traffic)
222254
}
255+
functionConf.needSetTraffic = inputs.traffic !== undefined && functionConf.lastVersion
256+
223257
functionConf.tags = ensureObject(tempFunctionConf.tags ? tempFunctionConf.tags : inputs.tag, {
224258
default: null
225259
})
@@ -264,11 +298,13 @@ const prepareInputs = async (instance, credentials, inputs = {}) => {
264298
{
265299
path: '/',
266300
enableCORS: apigatewayConf.enableCORS,
301+
serviceTimeout: apigatewayConf.serviceTimeout,
267302
method: 'ANY',
268303
function: {
269-
isIntegratedResponse: true,
304+
isIntegratedResponse: apigatewayConf.isIntegratedResponse === false ? false : true,
270305
functionName: functionConf.name,
271-
functionNamespace: functionConf.namespace
306+
functionNamespace: functionConf.namespace,
307+
functionQualifier: functionConf.needSetTraffic ? '$DEFAULT' : '$LATEST'
272308
}
273309
}
274310
]
@@ -353,7 +389,6 @@ const prepareInputs = async (instance, credentials, inputs = {}) => {
353389

354390
module.exports = {
355391
generateId,
356-
sleep,
357392
uploadCodeToCos,
358393
mergeJson,
359394
capitalString,

0 commit comments

Comments
 (0)