Skip to content

Commit 2dbecba

Browse files
authored
fix(triggers): apigw release bug for manager (#230)
* fix(trigger): apigw release bug for manager * fix(triggers): manager apigw release bug
1 parent 56bfc71 commit 2dbecba

File tree

10 files changed

+103
-28
lines changed

10 files changed

+103
-28
lines changed

__tests__/asw.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { sleep } from '@ygkit/request';
22
import Asw from '../src/modules/asw';
33
import { UpdateOptions, CreateResult } from './../src/modules/asw/interface';
44

5-
describe('Account', () => {
5+
describe('Asw', () => {
66
const credentials = {
77
SecretId: process.env.TENCENT_SECRET_ID,
88
SecretKey: process.env.TENCENT_SECRET_KEY,

__tests__/trigger.manager.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ describe('Trigger Manager', () => {
8585
];
8686

8787
test('bulk create triggers', async () => {
88-
const res = await client.bulkCreateTriggers(triggers);
88+
const { triggerList } = await client.bulkCreateTriggers(triggers);
8989

90-
expect(res).toEqual([
90+
expect(triggerList).toEqual([
9191
{
9292
name: functionConfig.name,
9393
triggers: [

src/modules/apigw/index.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,12 @@ export default class Apigw {
8282

8383
/** 部署 API 网关 */
8484
async deploy(inputs: ApigwDeployInputs) {
85-
const { environment = 'release' as const, oldState = {}, isInputServiceId = false } = inputs;
85+
const {
86+
environment = 'release' as const,
87+
oldState = {},
88+
isInputServiceId = false,
89+
isAutoRelease = false,
90+
} = inputs;
8691
if (isInputServiceId) {
8792
return this.deployWIthInputServiceId(inputs as ApigwDeployWithServiceIdInputs);
8893
}
@@ -107,7 +112,9 @@ export default class Apigw {
107112
environment,
108113
});
109114

110-
await this.service.release({ serviceId, environment });
115+
if (!isAutoRelease) {
116+
await this.service.release({ serviceId, environment });
117+
}
111118

112119
console.log(`Deploy service ${serviceId} success`);
113120

@@ -162,6 +169,7 @@ export default class Apigw {
162169
customDomains,
163170
usagePlan,
164171
isRemoveTrigger = false,
172+
isAutoRelease = true,
165173
} = inputs;
166174

167175
// check service exist
@@ -180,7 +188,7 @@ export default class Apigw {
180188

181189
// 定制化需求:如果用户在yaml中配置了 serviceId,则只执行删除 api 逻辑
182190
// 删除后需要重新发布
183-
if (isRemoveTrigger) {
191+
if (isRemoveTrigger && isAutoRelease) {
184192
await this.service.release({ serviceId, environment });
185193
return;
186194
}
@@ -240,7 +248,12 @@ export default class Apigw {
240248
}
241249

242250
async deployWIthInputServiceId(inputs: ApigwDeployWithServiceIdInputs) {
243-
const { environment = 'release' as const, oldState = {}, serviceId } = inputs;
251+
const {
252+
environment = 'release' as const,
253+
oldState = {},
254+
serviceId,
255+
isAutoRelease = true,
256+
} = inputs;
244257
inputs.protocols = getProtocolString(inputs.protocols as ('http' | 'https')[]);
245258

246259
const endpoints = inputs.endpoints || [];
@@ -255,7 +268,9 @@ export default class Apigw {
255268
environment,
256269
});
257270

258-
await this.service.release({ serviceId, environment });
271+
if (!isAutoRelease) {
272+
await this.service.release({ serviceId, environment });
273+
}
259274

260275
console.log(`Deploy service ${serviceId} success`);
261276

src/modules/apigw/interface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ export interface ApigwDeployInputs extends ApigwCreateServiceInputs, ApigwBindCu
174174
endpoints?: ApiEndpoint[];
175175
isInputServiceId?: boolean;
176176
isRemoveTrigger?: boolean;
177+
178+
// 是否自动发布服务(API 网关特有)
179+
isAutoRelease?: boolean;
177180
}
178181

179182
export type ApigwDeployWithServiceIdInputs = ApigwDeployInputs & { serviceId: string };
@@ -253,6 +256,7 @@ export interface ApigwRemoveInputs {
253256
usagePlan?: ApigwSetupUsagePlanInputs;
254257
isInputServiceId?: boolean;
255258
isRemoveTrigger?: boolean;
259+
isAutoRelease?: boolean;
256260
}
257261

258262
export interface ApiDetail {

src/modules/scf/entities/scf.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ export default class ScfEntity extends BaseEntity {
194194
// 更新函数接口不能传递以下参数
195195
delete reqInputs.Type;
196196
delete reqInputs.Handler;
197+
delete reqInputs.Runtime;
197198
delete reqInputs.Code;
198199
delete reqInputs.AsyncRunEnable;
199200
delete reqInputs.InstallDependency;

src/modules/scf/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ export default class Scf {
370370
await this.scf.isOperational({ namespace, functionName });
371371
} catch (e) {}
372372

373+
const { isAutoRelease = true } = inputs;
373374
const triggers = inputs.Triggers || inputs.triggers;
374375
if (triggers) {
375376
for (let i = 0; i < triggers.length; i++) {
@@ -378,6 +379,7 @@ export default class Scf {
378379
// delete apigw trigger
379380
const curTrigger = triggers[i];
380381
curTrigger.isRemoveTrigger = true;
382+
curTrigger.isAutoRelease = isAutoRelease;
381383
await this.apigwClient.remove(curTrigger as ApigwRemoveInputs);
382384
} catch (e) {
383385
console.log(e);
@@ -387,7 +389,6 @@ export default class Scf {
387389
}
388390

389391
await this.scf.delete({ namespace, functionName });
390-
391392
console.log(`Remove function ${functionName} success`);
392393

393394
return true;

src/modules/scf/interface.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ export interface ScfRemoveInputs {
278278

279279
Triggers?: ApigwRemoveInputs[] | Record<string, any>[];
280280
triggers?: ApigwRemoveInputs[] | Record<string, any>[];
281+
282+
// 是否自动发布 API 网关
283+
isAutoRelease?: boolean;
281284
}
282285

283286
export interface ScfInvokeInputs {

src/modules/triggers/apigw.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export default class ApigwTrigger extends BaseTrigger<ApigwTriggerInputsParams>
145145
funcInfo?: FunctionInfo;
146146
inputs: TriggerInputs<ApigwTriggerInputsParams>;
147147
}) {
148-
const { parameters } = inputs;
148+
const { parameters, isAutoRelease } = inputs;
149149
const {
150150
oldState,
151151
protocols,
@@ -158,6 +158,7 @@ export default class ApigwTrigger extends BaseTrigger<ApigwTriggerInputsParams>
158158
} = parameters!;
159159
const endpoints = parameters?.endpoints ?? [{ path: '/', method: 'ANY' }];
160160
const triggerInputs: ApigwTriggerInputsParams = {
161+
isAutoRelease,
161162
oldState: oldState ?? {},
162163
region,
163164
protocols,

src/modules/triggers/interface/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ export interface TriggerInputs<P extends TriggerInputsParams = TriggerInputsPara
126126
FunctionName?: string;
127127
Namespace?: string;
128128
Qualifier?: string;
129+
130+
// 是否自动发布服务(API 网关特有)
131+
isAutoRelease?: boolean;
129132
}
130133

131134
export interface TriggerDetail {
@@ -137,6 +140,8 @@ export interface TriggerDetail {
137140
compared?: boolean;
138141

139142
triggerType: string;
143+
144+
[key: string]: any;
140145
}
141146

142147
export interface NewTriggerInputs {
@@ -155,3 +160,10 @@ export interface NewTriggerInputs {
155160
}
156161

157162
export * from './clb';
163+
164+
export interface SimpleApigwDetail {
165+
functionName: string;
166+
serviceId: string;
167+
serviceName: string;
168+
environment: string;
169+
}

src/modules/triggers/manager.ts

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { SimpleApigwDetail } from './interface/index';
12
import { Capi } from '@tencent-sdk/capi';
2-
import { sleep } from '@ygkit/request';
33
import { ActionType } from '../scf/apis';
44
import { RegionType, ApiServiceType, CapiCredentials } from '../interface';
55
import { ApiError } from '../../utils/error';
@@ -105,7 +105,6 @@ export class TriggerManager {
105105
const deleteList: (TriggerDetail | null)[] = deepClone(oldList);
106106
const createList: (NewTriggerInputs | null)[] = deepClone(events);
107107
const deployList: (TriggerDetail | null)[] = [];
108-
// const noKeyTypes = ['apigw'];
109108
const updateList: (NewTriggerInputs | null)[] = [];
110109

111110
for (let index = 0; index < events.length; index++) {
@@ -175,6 +174,7 @@ export class TriggerManager {
175174
};
176175
}
177176

177+
// 删除函数触发器
178178
async removeTrigger({
179179
trigger,
180180
name,
@@ -209,7 +209,7 @@ export class TriggerManager {
209209
}
210210

211211
// 部署函数触发器
212-
async deployTrigger({
212+
async createTrigger({
213213
name,
214214
namespace = 'default',
215215
events = [],
@@ -242,6 +242,7 @@ export class TriggerManager {
242242
}
243243

244244
// 2. 创建新的触发器
245+
const apigwServiceList: SimpleApigwDetail[] = [];
245246
for (let i = 0; i < deployList.length; i++) {
246247
const trigger = deployList[i];
247248
const { Type } = trigger;
@@ -257,21 +258,27 @@ export class TriggerManager {
257258
credentials: this.credentials,
258259
region: this.region,
259260
});
260-
// 针对触发器创建接口限频,由于后端服务问题,必须设置并发为 1
261-
// TODO: 兼容多个网关触发器并行部署时,服务发布会报错,待后端接口支持状态查询后再额外改造 apigw 模块
262-
this.runningTasks++;
263-
if (this.runningTasks > this.maxRunningTasks) {
264-
await sleep(1000);
265-
}
261+
266262
const triggerOutput = await triggerInstance.create({
267263
scf: this,
268264
region: this.region,
269265
inputs: {
270266
namespace,
271267
functionName: name,
268+
// 禁用自动发布
269+
isAutoRelease: false,
272270
...trigger,
273271
},
274272
});
273+
// 筛选出 API 网关触发器,可以单独的进行发布
274+
if (triggerOutput.serviceId) {
275+
apigwServiceList.push({
276+
functionName: name,
277+
serviceId: triggerOutput.serviceId,
278+
serviceName: triggerOutput.serviceName,
279+
environment: triggerOutput.environment,
280+
});
281+
}
275282
this.runningTasks--;
276283

277284
deployList[i] = {
@@ -290,7 +297,7 @@ export class TriggerManager {
290297
name,
291298
triggers: deployList,
292299
};
293-
return outputs;
300+
return { outputs, apigwServiceList };
294301
}
295302

296303
/**
@@ -396,6 +403,32 @@ export class TriggerManager {
396403
});
397404
}
398405

406+
/**
407+
* 批量发布 API 网关,防止重复发布同一个网关
408+
* @param list API 网关列表
409+
*/
410+
async bulkReleaseApigw(list: SimpleApigwDetail[]) {
411+
// 筛选非重复的网关服务
412+
const uniqueList: SimpleApigwDetail[] = [];
413+
const map: { [key: string]: number } = {};
414+
list.forEach((item) => {
415+
if (!map[item.serviceId]) {
416+
map[item.serviceId] = 1;
417+
uniqueList.push(item);
418+
}
419+
});
420+
421+
const releaseTask: Promise<any>[] = [];
422+
for (let i = 0; i < uniqueList.length; i++) {
423+
const temp = uniqueList[i];
424+
const exist = await this.apigwClient.service.getById(temp.serviceId);
425+
if (exist) {
426+
releaseTask.push(this.apigwClient.service.release(temp));
427+
}
428+
}
429+
await Promise.all(releaseTask);
430+
}
431+
399432
/**
400433
* 批量处理多函数关联的触发器配置
401434
* @param triggers 触发器列表
@@ -404,28 +437,33 @@ export class TriggerManager {
404437
async bulkCreateTriggers(triggers: NewTriggerInputs[] = []) {
405438
const scfList = await this.getScfsByTriggers(triggers);
406439

407-
const createTasks: Promise<any>[] = [];
440+
let apigwList: SimpleApigwDetail[] = [];
441+
const res = [];
408442
for (let i = 0; i < scfList.length; i++) {
409443
const curScf = scfList[i];
410444
const triggersConfig = this.getScfTriggersConfig({
411445
name: curScf.name,
412446
triggers,
413447
});
414448
const task = async () => {
415-
const res = await this.deployTrigger({
449+
const { outputs, apigwServiceList } = await this.createTrigger({
416450
name: curScf.name,
417451
namespace: curScf.namespace,
418452
events: triggersConfig,
419453
});
420-
// this.runningTasks--;
421-
return res;
454+
apigwList = apigwList.concat(apigwServiceList);
455+
return outputs;
422456
};
423-
424-
createTasks.push(task());
457+
const temp = await task();
458+
res.push(temp);
425459
}
426-
const res = await Promise.all(createTasks);
427460

428-
return res;
461+
await this.bulkReleaseApigw(apigwList);
462+
463+
return {
464+
triggerList: res,
465+
apigwList,
466+
};
429467
}
430468

431469
/**

0 commit comments

Comments
 (0)