Skip to content

Commit 82224cb

Browse files
authored
fix: support async retry config (#238)
* fix(triggers): bulk create trigger delete old bug * fix(scf): support async retry config * chore: update jest config
1 parent 36d67d7 commit 82224cb

File tree

8 files changed

+152
-31
lines changed

8 files changed

+152
-31
lines changed

__tests__/scf/async.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { sleep } from '@ygkit/request';
2+
import { Scf } from '../../src';
3+
import { ScfDeployInputs } from '../../src/modules/scf/interface';
4+
5+
describe('Scf', () => {
6+
const credentials = {
7+
SecretId: process.env.TENCENT_SECRET_ID,
8+
SecretKey: process.env.TENCENT_SECRET_KEY,
9+
};
10+
const scf = new Scf(credentials);
11+
12+
const inputs: ScfDeployInputs = {
13+
name: `serverless-test-${Date.now()}`,
14+
code: {
15+
bucket: process.env.BUCKET,
16+
object: 'express_code.zip',
17+
},
18+
namespace: 'test',
19+
role: 'SCF_QcsRole',
20+
handler: 'sl_handler.handler',
21+
runtime: 'Nodejs12.16',
22+
region: 'ap-guangzhou',
23+
description: 'Created by Serverless',
24+
memorySize: 256,
25+
timeout: 20,
26+
tags: {
27+
test: 'test',
28+
},
29+
environment: {
30+
variables: {
31+
TEST: 'value',
32+
},
33+
},
34+
};
35+
let outputs;
36+
37+
test('[asyncRunEnable and traceEnable] create', async () => {
38+
await sleep(3000);
39+
delete inputs.cls;
40+
inputs.asyncRunEnable = true;
41+
inputs.traceEnable = true;
42+
inputs.msgTTL = 3600;
43+
inputs.retryNum = 0;
44+
outputs = await scf.deploy(inputs);
45+
46+
const asyncConfig = await scf.scf.getAsyncRetryConfig(inputs, {} as any);
47+
48+
expect(outputs.AsyncRunEnable).toBe('TRUE');
49+
expect(outputs.TraceEnable).toBe('TRUE');
50+
expect(asyncConfig).toEqual({
51+
AsyncTriggerConfig: {
52+
MsgTTL: 3600,
53+
RetryConfig: [
54+
{ ErrorCode: ['default'], RetryNum: 0, RetryInterval: 60 },
55+
{ ErrorCode: ['432'], RetryNum: -1, RetryInterval: 60 },
56+
],
57+
},
58+
RequestId: expect.any(String),
59+
});
60+
});
61+
test('[asyncRunEnable and traceEnable] update', async () => {
62+
await sleep(3000);
63+
inputs.asyncRunEnable = true;
64+
inputs.traceEnable = false;
65+
outputs = await scf.deploy(inputs);
66+
67+
expect(outputs.AsyncRunEnable).toBe('TRUE');
68+
expect(outputs.TraceEnable).toBe('FALSE');
69+
});
70+
test('[asyncRunEnable and traceEnable] remove', async () => {
71+
const res = await scf.remove({
72+
functionName: inputs.name,
73+
...outputs,
74+
});
75+
expect(res).toEqual(true);
76+
});
77+
});

__tests__/scf/base.test.ts

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -526,30 +526,4 @@ describe('Scf', () => {
526526
});
527527
expect(res).toEqual(true);
528528
});
529-
test('[asyncRunEnable and traceEnable] create', async () => {
530-
await sleep(3000);
531-
delete inputs.cls;
532-
inputs.asyncRunEnable = true;
533-
inputs.traceEnable = true;
534-
outputs = await scf.deploy(inputs);
535-
536-
expect(outputs.AsyncRunEnable).toBe('TRUE');
537-
expect(outputs.TraceEnable).toBe('TRUE');
538-
});
539-
test('[asyncRunEnable and traceEnable] update', async () => {
540-
await sleep(3000);
541-
inputs.asyncRunEnable = true;
542-
inputs.traceEnable = false;
543-
outputs = await scf.deploy(inputs);
544-
545-
expect(outputs.AsyncRunEnable).toBe('TRUE');
546-
expect(outputs.TraceEnable).toBe('FALSE');
547-
});
548-
test('[asyncRunEnable and traceEnable] remove', async () => {
549-
const res = await scf.remove({
550-
functionName: inputs.name,
551-
...outputs,
552-
});
553-
expect(res).toEqual(true);
554-
});
555529
});

jest.config.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ const config = {
88
silent: process.env.CI && !mod,
99
testTimeout: 600000,
1010
testEnvironment: 'node',
11-
testRegex: '/__tests__/.*\\.(test|spec)\\.(js|ts)$',
11+
testRegex: '/__tests__/[a-z]+/.*\\.(test|spec)\\.(js|ts)$',
1212
// 由于测试账号没有备案域名,所以线上 CI 忽略 CDN 测试
1313
testPathIgnorePatterns: [
1414
'/node_modules/',
1515
'/__tests__/cdn/',
16-
'/__tests__/apigw/apigw.custom-domains.test.ts',
17-
'/__tests__/scf/scf.sp.test.ts', // 专门用来验证测试小地域功能发布测试
18-
'/__tests__/scf/scf.http.test.ts', // 专门用来验证测试 HTTP 直通
16+
'/__tests__/apigw/custom-domains.test.ts',
17+
'/__tests__/scf/special.test.ts', // 专门用来验证测试小地域功能发布测试
18+
'/__tests__/scf/image.test.ts', // 专门用来验证测试镜像函数
19+
'/__tests__/scf/http.test.ts', // 专门用来验证测试 HTTP 直通
1920
'/__tests__/triggers/mps.test.ts',
2021
'/__tests__/triggers/manager.test.ts',
2122
],
@@ -34,6 +35,22 @@ if (mod) {
3435
config.testRegex = `/__tests__/${process.env.MODULE}/.*.test.(js|ts)`;
3536
config.testPathIgnorePatterns = ['/node_modules/'];
3637
}
38+
39+
if (mod === 'scf') {
40+
config.testPathIgnorePatterns = [
41+
'/node_modules/',
42+
'/__tests__/scf/special.test.ts', // 专门用来验证测试小地域功能发布测试
43+
'/__tests__/scf/image.test.ts', // 专门用来验证测试镜像函数
44+
'/__tests__/scf/http.test.ts', // 专门用来验证测试 HTTP 直通];
45+
];
46+
}
47+
if (mod === 'triggers') {
48+
config.testPathIgnorePatterns = [
49+
'/node_modules/',
50+
'/__tests__/triggers/mps.test.ts',
51+
'/__tests__/triggers/manager.test.ts',
52+
];
53+
}
3754
}
3855
}
3956

src/modules/scf/apis.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const ACTIONS = [
77
'GetFunction',
88
'UpdateFunctionCode',
99
'UpdateFunctionConfiguration',
10+
'GetFunctionEventInvokeConfig',
11+
'UpdateFunctionEventInvokeConfig',
1012
'CreateTrigger',
1113
'DeleteTrigger',
1214
'PublishVersion',

src/modules/scf/entities/scf.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,36 @@ export default class ScfEntity extends BaseEntity {
216216
return true;
217217
}
218218

219+
// 获取异步函数配置
220+
async getAsyncRetryConfig(inputs: ScfCreateFunctionInputs, funcInfo: FunctionInfo) {
221+
const reqParams = {
222+
Namespace: inputs.namespace || funcInfo.Namespace,
223+
FunctionName: inputs.name || funcInfo.FunctionName,
224+
Qualifier: inputs.qualifier || funcInfo.Qualifier || '$LATEST',
225+
};
226+
227+
const reqInputs: Partial<typeof reqParams> = reqParams;
228+
229+
const res = await this.request({ Action: 'GetFunctionEventInvokeConfig', ...reqInputs });
230+
return res;
231+
}
232+
async updateAsyncRetry(inputs: ScfCreateFunctionInputs, funcInfo: FunctionInfo) {
233+
console.log(`Updating function ${inputs.name} async retry configure, region ${this.region}`);
234+
const reqParams = {
235+
Namespace: inputs.namespace || funcInfo.Namespace,
236+
FunctionName: inputs.name || funcInfo.FunctionName,
237+
AsyncTriggerConfig: {
238+
MsgTTL: inputs.msgTTL || 21600,
239+
RetryConfig: [{ RetryNum: inputs.retryNum ?? 2 }],
240+
},
241+
};
242+
243+
const reqInputs: Partial<typeof reqParams> = reqParams;
244+
245+
await this.request({ Action: 'UpdateFunctionEventInvokeConfig', ...reqInputs });
246+
return true;
247+
}
248+
219249
// delete function
220250
async delete({ namespace, functionName }: { namespace: string; functionName: string }) {
221251
namespace = namespace || CONFIGS.defaultNamespace;

src/modules/scf/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,13 @@ export default class Scf {
288288
await this.scf.updateConfigure(inputs, funcInfo);
289289
}
290290

291+
await this.scf.isOperational({ namespace, functionName });
292+
293+
// 如果是异步函数,判断是否需要更新异步调用重试配置
294+
if (inputs.asyncRunEnable) {
295+
await this.scf.updateAsyncRetry(inputs, funcInfo!);
296+
}
297+
291298
funcInfo = await this.scf.isOperational({ namespace, functionName });
292299

293300
const outputs = (funcInfo as any) || ({} as ScfDeployOutputs);

src/modules/scf/interface.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export interface FunctionInfo {
8787
Tags: Tag[];
8888
ClsLogsetId: string;
8989
ClsTopicId: string;
90+
Qualifier: string;
9091
}
9192

9293
export interface ScfPublishVersionInputs {
@@ -192,6 +193,8 @@ export interface ScfCreateFunctionInputs {
192193
userId?: string;
193194
}[];
194195

196+
qualifier?: string;
197+
195198
asyncRunEnable?: undefined | boolean;
196199
traceEnable?: undefined | boolean;
197200
installDependency?: undefined | boolean;
@@ -209,6 +212,10 @@ export interface ScfCreateFunctionInputs {
209212
// 启动命令参数
210213
args?: string;
211214
};
215+
216+
// 异步调用重试配置
217+
msgTTL?: number; // 消息保留时间,单位秒
218+
retryNum?: number; // 重试次数
212219
}
213220

214221
export interface ScfUpdateAliasTrafficInputs {

src/modules/triggers/manager.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,14 @@ export class TriggerManager {
202202
}
203203
}
204204
return {
205-
deleteList: deleteList.filter((item) => item) as TriggerDetail[],
205+
deleteList: deleteList
206+
.filter((item) => item)
207+
.map((item) => {
208+
return {
209+
...item,
210+
triggerType: item?.Type,
211+
};
212+
}) as TriggerDetail[],
206213
deployList: deployList.map((item) => {
207214
delete item?.compared;
208215
return item as TriggerDetail;

0 commit comments

Comments
 (0)