@@ -31,13 +31,12 @@ class Scf {
31
31
return result ;
32
32
}
33
33
34
- // 绑定默认策略
34
+ // bind SCF_QcsRole role
35
35
async bindScfQCSRole ( ) {
36
36
console . log ( `Creating and binding SCF_QcsRole` ) ;
37
37
const camClient = new Cam ( this . credentials ) ;
38
38
const roleName = 'SCF_QcsRole' ;
39
39
const policyId = 28341895 ;
40
- // 创建默认角色
41
40
try {
42
41
await camClient . request ( {
43
42
Action : 'CreateRole' ,
@@ -58,7 +57,6 @@ class Scf {
58
57
} ) ,
59
58
} ) ;
60
59
} catch ( e ) { }
61
- // 绑定默认策略
62
60
try {
63
61
await camClient . request ( {
64
62
Action : 'AttachRolePolicy' ,
@@ -99,21 +97,27 @@ class Scf {
99
97
// because creating/upadting function is asynchronous
100
98
// if not become Active in 120 * 1000 miniseconds, return request result, and throw error
101
99
async checkStatus ( namespace = 'default' , functionName , qualifier = '$LATEST' ) {
102
- console . log ( `Checking function ${ functionName } status` ) ;
103
100
let initialInfo = await this . getFunction ( namespace , functionName , qualifier ) ;
104
- let status = initialInfo ;
101
+ let { Status } = initialInfo ;
105
102
let times = 120 ;
106
- while ( CONFIGS . waitStatus . indexOf ( status ) !== - 1 && times > 0 ) {
103
+ while ( CONFIGS . waitStatus . indexOf ( Status ) !== - 1 && times > 0 ) {
107
104
initialInfo = await this . getFunction ( namespace , functionName , qualifier ) ;
108
- status = initialInfo . Status ;
105
+ if ( ! initialInfo ) {
106
+ return true ;
107
+ }
108
+ ( { Status } = initialInfo ) ;
109
+ // if change to failed status break loop
110
+ if ( CONFIGS . failStatus . indexOf ( Status ) !== - 1 ) {
111
+ break ;
112
+ }
109
113
await sleep ( 1000 ) ;
110
114
times = times - 1 ;
111
115
}
112
116
const { StatusReasons } = initialInfo ;
113
- return status !== 'Active'
117
+ return Status !== 'Active'
114
118
? StatusReasons && StatusReasons . length > 0
115
119
? `函数状态异常, ${ StatusReasons [ 0 ] . ErrorMessage } `
116
- : `函数状态异常, ${ status } `
120
+ : `函数状态异常, ${ Status } `
117
121
: true ;
118
122
}
119
123
@@ -237,7 +241,7 @@ class Scf {
237
241
}
238
242
239
243
// 删除函数
240
- async deleteFunction ( functionName , namespace ) {
244
+ async deleteFunction ( namespace , functionName ) {
241
245
await this . request ( {
242
246
Action : 'DeleteFunction' ,
243
247
FunctionName : functionName ,
@@ -315,7 +319,7 @@ class Scf {
315
319
}
316
320
317
321
/**
318
- * check whether function status is operational
322
+ * check whether function status is operational, mostly for asynchronous operation
319
323
* @param {string } namespace
320
324
* @param {string } functionName funcitn name
321
325
*/
@@ -328,15 +332,63 @@ class Scf {
328
332
throw new TypeError ( 'API_SCF_isOperationalStatus' , res ) ;
329
333
}
330
334
335
+ async tryToDeleteFunction ( namespace , functionName ) {
336
+ try {
337
+ console . log ( `正在尝试删除创建失败的函数,命令空间:${ namespace } ,函数名称:${ functionName } ` ) ;
338
+ await this . deleteFunction ( namespace , functionName ) ;
339
+ await this . isOperationalStatus ( namespace , functionName ) ;
340
+ } catch ( e ) { }
341
+ }
342
+
343
+ // check whether scf is operational
344
+ async isOperational ( namespace , functionName , qualifier = '$LATEST' ) {
345
+ const funcInfo = await this . getFunction ( namespace , functionName , qualifier ) ;
346
+ if ( funcInfo ) {
347
+ const { Status, StatusReasons } = funcInfo ;
348
+ const reason = StatusReasons && StatusReasons . length > 0 ? StatusReasons [ 0 ] . ErrorMessage : '' ;
349
+ if ( Status === 'Active' ) {
350
+ return true ;
351
+ }
352
+ let errorMsg = '' ;
353
+ switch ( Status ) {
354
+ case 'Creating' :
355
+ errorMsg = '当前函数正在创建中,无法更新代码,请稍后再试' ;
356
+ break ;
357
+ case 'Updating' :
358
+ errorMsg = '当前函数正在更新中,无法更新代码,请稍后再试' ;
359
+ break ;
360
+ case 'Publishing' :
361
+ errorMsg = '当前函数正在版本发布中,无法更新代码,请稍后再试' ;
362
+ break ;
363
+ case 'Deleting' :
364
+ errorMsg = '当前函数正在删除中,无法更新代码,请稍后再试' ;
365
+ break ;
366
+ case 'CreateFailed' :
367
+ console . log ( `函数创建失败,${ reason || Status } ` ) ;
368
+ await this . tryToDeleteFunction ( namespace , functionName ) ;
369
+ break ;
370
+ case 'DeleteFailed' :
371
+ errorMsg = `函数删除失败,${ reason || Status } ` ;
372
+ break ;
373
+ }
374
+ if ( errorMsg ) {
375
+ throw new TypeError ( 'API_SCF_isOperational' , errorMsg ) ;
376
+ }
377
+ }
378
+ }
379
+
331
380
// deploy SCF flow
332
381
async deploy ( inputs = { } ) {
382
+ const namespace = inputs . namespace || CONFIGS . defaultNamespace ;
383
+
384
+ // before deploy a scf, we should check whether
385
+ // if is CreateFailed, try to remove it
386
+ await this . isOperational ( namespace , inputs . name ) ;
387
+
333
388
// whether auto create/bind role
334
389
if ( inputs . enableRoleAuth ) {
335
390
await this . bindScfQCSRole ( ) ;
336
391
}
337
-
338
- const namespace = inputs . namespace || CONFIGS . defaultNamespace ;
339
-
340
392
// check SCF exist
341
393
// exist: update it, not: create it
342
394
let funcInfo = await this . getFunction ( namespace , inputs . name ) ;
@@ -452,7 +504,7 @@ class Scf {
452
504
return ;
453
505
}
454
506
455
- await this . deleteFunction ( functionName , namespace ) ;
507
+ await this . deleteFunction ( namespace , functionName ) ;
456
508
457
509
if ( inputs . Triggers ) {
458
510
for ( let i = 0 ; i < inputs . Triggers . length ; i ++ ) {
0 commit comments