@cloudbase/manager-node 3.10.0 → 3.12.1-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -628,6 +628,121 @@ class FunctionService {
628
628
  LayerVersion: version
629
629
  });
630
630
  }
631
+ /**
632
+ * 设置预置并发
633
+ * @private
634
+ * @param {IProvisionedConcurrencyConfig} concurrencyConfig
635
+ * @returns
636
+ * @memberof FunctionService
637
+ */
638
+ async setProvisionedConcurrencyConfig(concurrencyConfig) {
639
+ const { namespace } = this.getFunctionConfig();
640
+ const { functionName: FunctionName, qualifier: Qualifier, versionProvisionedConcurrencyNum: VersionProvisionedConcurrencyNum } = concurrencyConfig;
641
+ return this.scfService.request('PutProvisionedConcurrencyConfig', {
642
+ FunctionName,
643
+ Qualifier,
644
+ VersionProvisionedConcurrencyNum,
645
+ Namespace: namespace
646
+ });
647
+ }
648
+ /**
649
+ * 获取函数预置并发详情
650
+ * @private
651
+ * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
652
+ * @returns {Promise<IGetProvisionedConcurrencyRes>}
653
+ * @memberof FunctionService
654
+ */
655
+ async getProvisionedConcurrencyConfig(concurrencyConfig) {
656
+ const { namespace } = this.getFunctionConfig();
657
+ const { functionName: FunctionName, qualifier: Qualifier } = concurrencyConfig;
658
+ return this.scfService.request('GetProvisionedConcurrencyConfig', {
659
+ FunctionName,
660
+ Qualifier,
661
+ Namespace: namespace
662
+ });
663
+ }
664
+ /**
665
+ * 删除预置并发
666
+ * @private
667
+ * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
668
+ * @returns {Promise<IResponseInfo>}
669
+ * @memberof FunctionService
670
+ */
671
+ async deleteProvisionedConcurrencyConfig(concurrencyConfig) {
672
+ const { namespace } = this.getFunctionConfig();
673
+ const { functionName: FunctionName, qualifier: Qualifier } = concurrencyConfig;
674
+ return this.scfService.request('DeleteProvisionedConcurrencyConfig', {
675
+ FunctionName,
676
+ Qualifier,
677
+ Namespace: namespace
678
+ });
679
+ }
680
+ /**
681
+ * 发布新版本
682
+ * @param {IPublishVersionParams} publishParams
683
+ * @returns {Promise<IPublishVersionRes>}
684
+ * @memberof FunctionService
685
+ */
686
+ async publishVersion(publishParams) {
687
+ const { namespace } = this.getFunctionConfig();
688
+ const { functionName: FunctionName, description: Description } = publishParams;
689
+ return this.scfService.request('PublishVersion', {
690
+ FunctionName,
691
+ Description,
692
+ Namespace: namespace
693
+ });
694
+ }
695
+ /**
696
+ * 查询函数版本详情
697
+ * @param {IListFunctionVersionParams} listVersionParams
698
+ * @returns {Promise<IFunctionVersionsRes>}
699
+ * @memberof FunctionService
700
+ */
701
+ async listVersionByFunction(listVersionParams) {
702
+ const { namespace } = this.getFunctionConfig();
703
+ const { functionName: FunctionName, offset: Offset, limit: Limit, order: Order, orderBy: OrderBy } = listVersionParams;
704
+ return this.scfService.request('ListVersionByFunction', {
705
+ FunctionName,
706
+ Namespace: namespace,
707
+ Offset,
708
+ Limit,
709
+ Order,
710
+ OrderBy
711
+ });
712
+ }
713
+ /**
714
+ *
715
+ * @param {IUpdateFunctionAliasConfig} updateVersionConfigParams
716
+ * @returns {Promise<IResponseInfo>}
717
+ * @memberof FunctionService
718
+ */
719
+ async updateFunctionAliasConfig(updateVersionConfigParams) {
720
+ const { namespace } = this.getFunctionConfig();
721
+ const { functionName: FunctionName, name: Name, functionVersion: FunctionVersion, routingConfig: RoutingConfig, description: Description } = updateVersionConfigParams;
722
+ return this.scfService.request('UpdateAlias', {
723
+ FunctionName,
724
+ Name,
725
+ Namespace: namespace,
726
+ FunctionVersion,
727
+ RoutingConfig,
728
+ Description
729
+ });
730
+ }
731
+ /**
732
+ * 查询函数别名详情
733
+ * @param {IGetFunctionAlias} params
734
+ * @returns {Promise<IGetFunctionAliasRes>}
735
+ * @memberof FunctionService
736
+ */
737
+ async getFunctionAlias(params) {
738
+ const { namespace } = this.getFunctionConfig();
739
+ const { functionName: FunctionName, name: Name } = params;
740
+ return this.scfService.request('GetAlias', {
741
+ FunctionName,
742
+ Name,
743
+ Namespace: namespace
744
+ });
745
+ }
631
746
  async createAccessPath(name, path) {
632
747
  const access = this.environment.getAccessService();
633
748
  try {
@@ -856,6 +971,27 @@ __decorate([
856
971
  __decorate([
857
972
  utils_1.preLazy()
858
973
  ], FunctionService.prototype, "getLayerVersion", null);
974
+ __decorate([
975
+ utils_1.preLazy()
976
+ ], FunctionService.prototype, "setProvisionedConcurrencyConfig", null);
977
+ __decorate([
978
+ utils_1.preLazy()
979
+ ], FunctionService.prototype, "getProvisionedConcurrencyConfig", null);
980
+ __decorate([
981
+ utils_1.preLazy()
982
+ ], FunctionService.prototype, "deleteProvisionedConcurrencyConfig", null);
983
+ __decorate([
984
+ utils_1.preLazy()
985
+ ], FunctionService.prototype, "publishVersion", null);
986
+ __decorate([
987
+ utils_1.preLazy()
988
+ ], FunctionService.prototype, "listVersionByFunction", null);
989
+ __decorate([
990
+ utils_1.preLazy()
991
+ ], FunctionService.prototype, "updateFunctionAliasConfig", null);
992
+ __decorate([
993
+ utils_1.preLazy()
994
+ ], FunctionService.prototype, "getFunctionAlias", null);
859
995
  __decorate([
860
996
  utils_1.preLazy()
861
997
  ], FunctionService.prototype, "createAccessPath", null);
@@ -131,7 +131,7 @@ class HostingService {
131
131
  * @param options
132
132
  */
133
133
  async uploadFiles(options) {
134
- const { localPath, cloudPath, files = [], onProgress, onFileFinish, parallel = 20, ignore } = options;
134
+ const { localPath, cloudPath, files = [], onProgress, onFileFinish, parallel = 20, ignore, retryCount, retryInterval } = options;
135
135
  const hosting = await this.checkStatus();
136
136
  const { Bucket, Regoin } = hosting;
137
137
  const storageService = await this.environment.getStorageService();
@@ -150,7 +150,9 @@ class HostingService {
150
150
  onProgress,
151
151
  onFileFinish,
152
152
  fileId: false,
153
- ignore
153
+ ignore,
154
+ retryCount,
155
+ retryInterval,
154
156
  });
155
157
  }
156
158
  else {
@@ -171,7 +173,9 @@ class HostingService {
171
173
  bucket: Bucket,
172
174
  region: Regoin,
173
175
  files: uploadFiles,
174
- fileId: false
176
+ fileId: false,
177
+ retryCount,
178
+ retryInterval,
175
179
  });
176
180
  }
177
181
  /**
@@ -49,7 +49,7 @@ class StorageService {
49
49
  * @param options
50
50
  */
51
51
  async uploadFiles(options) {
52
- const { files, onProgress, parallel, onFileFinish, ignore } = options;
52
+ const { files, onProgress, parallel, onFileFinish, ignore, retryCount, retryInterval } = options;
53
53
  const { bucket, region } = this.getStorageConfig();
54
54
  return this.uploadFilesCustom({
55
55
  files,
@@ -58,7 +58,9 @@ class StorageService {
58
58
  ignore,
59
59
  parallel,
60
60
  onProgress,
61
- onFileFinish
61
+ onFileFinish,
62
+ retryCount,
63
+ retryInterval
62
64
  });
63
65
  }
64
66
  /**
@@ -257,7 +259,7 @@ class StorageService {
257
259
  * @param options
258
260
  */
259
261
  async uploadFilesCustom(options) {
260
- const { files, bucket, region, ignore, onProgress, onFileFinish, fileId = true, parallel = 20 } = options;
262
+ const { files, bucket, region, ignore, onProgress, onFileFinish, fileId = true, parallel = 20, retryCount = 0, retryInterval = 500 } = options;
261
263
  if (!files || !files.length) {
262
264
  return;
263
265
  }
@@ -291,11 +293,24 @@ class StorageService {
291
293
  fileList = await asyncTaskController.run();
292
294
  const cos = this.getCos(parallel);
293
295
  const uploadFiles = util_1.default.promisify(cos.uploadFiles).bind(cos);
294
- return uploadFiles({
295
- onProgress,
296
- onFileFinish,
296
+ const params = {
297
297
  files: fileList,
298
- SliceSize: BIG_FILE_SIZE
298
+ SliceSize: BIG_FILE_SIZE,
299
+ onProgress,
300
+ onFileFinish
301
+ };
302
+ // return uploadFiles({
303
+ // onProgress,
304
+ // onFileFinish,
305
+ // files: fileList,
306
+ // SliceSize: BIG_FILE_SIZE
307
+ // })
308
+ return this.uploadFilesWithRetry({
309
+ uploadFiles,
310
+ options: params,
311
+ times: retryCount,
312
+ interval: retryInterval,
313
+ failedFiles: []
299
314
  });
300
315
  }
301
316
  /**
@@ -367,27 +382,32 @@ class StorageService {
367
382
  * @returns {Promise<(NodeJS.ReadableStream | string)[]>}
368
383
  */
369
384
  async downloadDirectory(options) {
370
- const { cloudPath, localPath } = options;
385
+ const { cloudPath, localPath, parallel = 20 } = options;
371
386
  const resolveLocalPath = path_1.default.resolve(localPath);
372
387
  utils_1.checkFullAccess(resolveLocalPath, true);
373
388
  const cloudDirectoryKey = this.getCloudKey(cloudPath);
374
389
  const files = await this.walkCloudDir(cloudDirectoryKey);
375
- const promises = files.map(async (file) => {
376
- const fileRelativePath = file.Key.replace(cloudDirectoryKey, '');
377
- // 空路径和文件夹跳过
378
- if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
379
- return;
380
- }
381
- const localFilePath = path_1.default.join(resolveLocalPath, fileRelativePath);
382
- // 创建文件的父文件夹
383
- const fileDir = path_1.default.dirname(localFilePath);
384
- await make_dir_1.default(fileDir);
385
- return this.downloadFile({
386
- cloudPath: file.Key,
387
- localPath: localFilePath
388
- });
390
+ const promises = files.map(file => async () => {
391
+ return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath });
389
392
  });
390
- return Promise.all(promises);
393
+ const asyncTaskController = new parallel_1.AsyncTaskParallelController(parallel, 50);
394
+ asyncTaskController.loadTasks(promises);
395
+ let res = await asyncTaskController.run();
396
+ const errorIndexArr = [];
397
+ res.map((item, index) => /Error/gi.test(Object.prototype.toString.call(item)) && errorIndexArr.push(index));
398
+ // 重试逻辑
399
+ if (errorIndexArr.length) {
400
+ const errorFiles = errorIndexArr.map(errorIndex => files[errorIndex]);
401
+ asyncTaskController.loadTasks(errorFiles.map(file => async () => {
402
+ return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath });
403
+ }));
404
+ res = await asyncTaskController.run();
405
+ }
406
+ const errorResultArr = this.determineDownLoadResultIsError(res);
407
+ if (errorResultArr.length) {
408
+ throw errorResultArr[0];
409
+ }
410
+ return res;
391
411
  }
392
412
  /**
393
413
  * 列出文件夹下的文件
@@ -790,7 +810,6 @@ class StorageService {
790
810
  params.WebsiteConfiguration.RoutingRules.push(routeItem);
791
811
  }
792
812
  }
793
- console.log('params:', JSON.stringify(params));
794
813
  const res = await putBucketWebsite(params);
795
814
  return res;
796
815
  }
@@ -873,31 +892,75 @@ class StorageService {
873
892
  * @returns
874
893
  */
875
894
  async uploadFilesWithRetry({ uploadFiles, options, times, interval, failedFiles }) {
876
- console.log('times', times);
877
895
  const { files, onFileFinish } = options;
878
896
  const tempFailedFiles = [];
897
+ let curError = null;
879
898
  const res = await uploadFiles(Object.assign(Object.assign({}, options), { files: failedFiles.length
880
899
  ? files.filter(file => failedFiles.includes(file.Key))
881
900
  : files, onFileFinish: (...args) => {
882
- console.log('args', args);
883
901
  const error = args[0];
884
902
  const fileInfo = args[2];
885
903
  if (error) {
904
+ curError = error;
886
905
  tempFailedFiles.push(fileInfo.Key);
887
906
  }
888
907
  onFileFinish === null || onFileFinish === void 0 ? void 0 : onFileFinish.apply(null, args);
889
908
  } }));
890
- if (!(tempFailedFiles === null || tempFailedFiles === void 0 ? void 0 : tempFailedFiles.length) || times <= 0)
909
+ // if (!tempFailedFiles?.length || times <= 0) return res
910
+ if (!(tempFailedFiles === null || tempFailedFiles === void 0 ? void 0 : tempFailedFiles.length)) {
891
911
  return res;
892
- if (times > 0) {
893
- setTimeout(() => this.uploadFilesWithRetry({
894
- uploadFiles,
895
- options,
896
- times: times - 1,
897
- interval,
898
- failedFiles: tempFailedFiles
899
- }), interval);
900
912
  }
913
+ else {
914
+ if (times > 0) {
915
+ return await new Promise((resolve, reject) => {
916
+ setTimeout(() => this.uploadFilesWithRetry({
917
+ uploadFiles,
918
+ options,
919
+ times: times - 1,
920
+ interval,
921
+ failedFiles: tempFailedFiles
922
+ }).then(res => resolve(res))
923
+ .catch(err => reject(err)), interval);
924
+ });
925
+ }
926
+ else {
927
+ if (curError) {
928
+ throw curError;
929
+ }
930
+ }
931
+ }
932
+ }
933
+ /**
934
+ * 拼接路径下载单文件
935
+ * @param file
936
+ * @param cloudDirectoryKey
937
+ * @param resolveLocalPath
938
+ * @returns
939
+ */
940
+ async downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath }) {
941
+ const fileRelativePath = file.Key.replace(cloudDirectoryKey, '');
942
+ // 空路径和文件夹跳过
943
+ if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
944
+ return;
945
+ }
946
+ const localFilePath = path_1.default.join(resolveLocalPath, fileRelativePath);
947
+ // 创建文件的父文件夹
948
+ const fileDir = path_1.default.dirname(localFilePath);
949
+ await make_dir_1.default(fileDir);
950
+ return this.downloadFile({
951
+ cloudPath: file.Key,
952
+ localPath: localFilePath
953
+ });
954
+ }
955
+ /**
956
+ * 根据下载结果返回错误列表
957
+ * @param res
958
+ * @returns
959
+ */
960
+ determineDownLoadResultIsError(res) {
961
+ const resultErrorArr = [];
962
+ res.map(item => /Error/gi.test(Object.prototype.toString.call(item)) && resultErrorArr.push(item));
963
+ return resultErrorArr;
901
964
  }
902
965
  }
903
966
  __decorate([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/manager-node",
3
- "version": "3.10.0",
3
+ "version": "3.12.1-beta",
4
4
  "description": "The node manage service api for cloudbase.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -126,6 +126,107 @@ export interface IGetLayerVersionRes extends IResponseInfo {
126
126
  Status: string // 层的具体版本当前状态
127
127
  }
128
128
 
129
+ export interface ISetProvisionedConcurrencyConfig {
130
+ functionName: string
131
+ qualifier: string
132
+ versionProvisionedConcurrencyNum: number
133
+ }
134
+
135
+ export interface IGetProvisionedConcurrencyConfig {
136
+ functionName: string
137
+ qualifier?: string
138
+ }
139
+
140
+ export interface IVersionProvisionedConcurrencyInfo {
141
+ AllocatedProvisionedConcurrencyNum: number // 设置的预置并发数。
142
+ AvailableProvisionedConcurrencyNum: number // 当前已完成预置的并发数。
143
+ Status: string // 预置任务状态,Done表示已完成,InProgress表示进行中,Failed表示部分或全部失败。
144
+ StatusReason: string // 对预置任务状态Status的说明。
145
+ Qualifier: string // 版本号
146
+ }
147
+ export interface IGetProvisionedConcurrencyRes extends IResponseInfo {
148
+ UnallocatedConcurrencyNum: number
149
+ Allocated: IVersionProvisionedConcurrencyInfo[]
150
+ }
151
+
152
+ export interface IPublishVersionParams {
153
+ functionName: string
154
+ description?: string
155
+ }
156
+
157
+ export interface IPublishVersionRes extends IResponseInfo {
158
+ FunctionVersion: string
159
+ CodeSize: number
160
+ MemorySize: number
161
+ Description: string
162
+ Handler: string
163
+ Timeout: number
164
+ Runtime: string
165
+ Namespace: string
166
+ }
167
+
168
+
169
+ export interface IListFunctionVersionParams {
170
+ functionName: string
171
+ offset?: number
172
+ limit?: number
173
+ order?: string
174
+ orderBy?: string
175
+ }
176
+
177
+ export interface IFunctionVersion {
178
+ Version: string
179
+ Description: string
180
+ AddTime: string
181
+ ModTime: string
182
+ Status: string //
183
+ }
184
+
185
+ export interface IFunctionVersionsRes extends IResponseInfo {
186
+ FunctionVersion: string[]
187
+ Versions: IFunctionVersion[]
188
+ TotalCount: number
189
+ }
190
+
191
+ export interface IVersionMatch {
192
+ Version: string // 函数版本名称
193
+ Key: string // 匹配规则的key,调用时通过传key来匹配规则路由到指定版本 header方式:key填写"invoke.headers.User",并在 invoke 调用函数时传参 RoutingKey:{"User":"value"}规则匹配调用
194
+ Method: string // 匹配方式。取值范围:range:范围匹配 exact:字符串精确匹配
195
+ Expression: string //
196
+ }
197
+
198
+ export interface IVersionWeight {
199
+ Version: string
200
+ Weight: number
201
+ }
202
+
203
+ export interface IRoutingConfig {
204
+ AdditionalVersionWeights?: IVersionWeight[]
205
+ AddtionVersionMatchs?: IVersionMatch[]
206
+ }
207
+
208
+ export interface IUpdateFunctionAliasConfig {
209
+ functionName: string // 函数名
210
+ name: string // 函数别名 如$DEFAULT
211
+ functionVersion: string // 函数版本
212
+ description?: string // 别名描述
213
+ routingConfig?: IRoutingConfig
214
+ }
215
+
216
+ export interface IGetFunctionAlias {
217
+ functionName: string // 函数名称
218
+ name: string // 别名
219
+ }
220
+
221
+ export interface IGetFunctionAliasRes extends IResponseInfo {
222
+ FunctionVersion: string
223
+ Name: string
224
+ RoutingConfig: IRoutingConfig
225
+ Description: string
226
+ AddTime: string
227
+ ModTime: string
228
+ }
229
+
129
230
  // 是否为 Node 函数
130
231
  function isNodeFunction(runtime: string) {
131
232
  // 不严格限制
@@ -913,6 +1014,142 @@ export class FunctionService {
913
1014
  })
914
1015
  }
915
1016
 
1017
+ /**
1018
+ * 设置预置并发
1019
+ * @private
1020
+ * @param {IProvisionedConcurrencyConfig} concurrencyConfig
1021
+ * @returns
1022
+ * @memberof FunctionService
1023
+ */
1024
+ @preLazy()
1025
+ public async setProvisionedConcurrencyConfig(concurrencyConfig: ISetProvisionedConcurrencyConfig): Promise<IResponseInfo> {
1026
+ const { namespace } = this.getFunctionConfig()
1027
+ const { functionName: FunctionName, qualifier: Qualifier, versionProvisionedConcurrencyNum: VersionProvisionedConcurrencyNum } = concurrencyConfig
1028
+
1029
+ return this.scfService.request('PutProvisionedConcurrencyConfig', {
1030
+ FunctionName,
1031
+ Qualifier,
1032
+ VersionProvisionedConcurrencyNum,
1033
+ Namespace: namespace
1034
+ })
1035
+ }
1036
+
1037
+ /**
1038
+ * 获取函数预置并发详情
1039
+ * @private
1040
+ * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
1041
+ * @returns {Promise<IGetProvisionedConcurrencyRes>}
1042
+ * @memberof FunctionService
1043
+ */
1044
+ @preLazy()
1045
+ public async getProvisionedConcurrencyConfig(concurrencyConfig: IGetProvisionedConcurrencyConfig): Promise<IGetProvisionedConcurrencyRes> {
1046
+ const { namespace } = this.getFunctionConfig()
1047
+ const { functionName: FunctionName, qualifier: Qualifier } = concurrencyConfig
1048
+
1049
+ return this.scfService.request('GetProvisionedConcurrencyConfig', {
1050
+ FunctionName,
1051
+ Qualifier,
1052
+ Namespace: namespace
1053
+ })
1054
+ }
1055
+
1056
+ /**
1057
+ * 删除预置并发
1058
+ * @private
1059
+ * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
1060
+ * @returns {Promise<IResponseInfo>}
1061
+ * @memberof FunctionService
1062
+ */
1063
+ @preLazy()
1064
+ public async deleteProvisionedConcurrencyConfig(concurrencyConfig: IGetProvisionedConcurrencyConfig): Promise<IResponseInfo> {
1065
+ const { namespace } = this.getFunctionConfig()
1066
+ const { functionName: FunctionName, qualifier: Qualifier } = concurrencyConfig
1067
+
1068
+ return this.scfService.request('DeleteProvisionedConcurrencyConfig', {
1069
+ FunctionName,
1070
+ Qualifier,
1071
+ Namespace: namespace
1072
+ })
1073
+ }
1074
+
1075
+ /**
1076
+ * 发布新版本
1077
+ * @param {IPublishVersionParams} publishParams
1078
+ * @returns {Promise<IPublishVersionRes>}
1079
+ * @memberof FunctionService
1080
+ */
1081
+ @preLazy()
1082
+ public async publishVersion(publishParams: IPublishVersionParams): Promise<IPublishVersionRes> {
1083
+ const { namespace } = this.getFunctionConfig()
1084
+ const { functionName: FunctionName, description: Description } = publishParams
1085
+
1086
+ return this.scfService.request('PublishVersion', {
1087
+ FunctionName,
1088
+ Description,
1089
+ Namespace: namespace
1090
+ })
1091
+ }
1092
+
1093
+ /**
1094
+ * 查询函数版本详情
1095
+ * @param {IListFunctionVersionParams} listVersionParams
1096
+ * @returns {Promise<IFunctionVersionsRes>}
1097
+ * @memberof FunctionService
1098
+ */
1099
+ @preLazy()
1100
+ public async listVersionByFunction(listVersionParams: IListFunctionVersionParams): Promise<IFunctionVersionsRes> {
1101
+ const { namespace } = this.getFunctionConfig()
1102
+ const { functionName: FunctionName, offset: Offset, limit: Limit, order: Order, orderBy: OrderBy } = listVersionParams
1103
+
1104
+ return this.scfService.request('ListVersionByFunction', {
1105
+ FunctionName,
1106
+ Namespace: namespace,
1107
+ Offset,
1108
+ Limit,
1109
+ Order,
1110
+ OrderBy
1111
+ })
1112
+ }
1113
+
1114
+ /**
1115
+ *
1116
+ * @param {IUpdateFunctionAliasConfig} updateVersionConfigParams
1117
+ * @returns {Promise<IResponseInfo>}
1118
+ * @memberof FunctionService
1119
+ */
1120
+ @preLazy()
1121
+ public async updateFunctionAliasConfig(updateVersionConfigParams: IUpdateFunctionAliasConfig): Promise<IResponseInfo> {
1122
+ const { namespace } = this.getFunctionConfig()
1123
+ const { functionName: FunctionName, name: Name, functionVersion: FunctionVersion, routingConfig: RoutingConfig, description: Description } = updateVersionConfigParams
1124
+
1125
+ return this.scfService.request('UpdateAlias', {
1126
+ FunctionName,
1127
+ Name,
1128
+ Namespace: namespace,
1129
+ FunctionVersion,
1130
+ RoutingConfig,
1131
+ Description
1132
+ })
1133
+ }
1134
+
1135
+ /**
1136
+ * 查询函数别名详情
1137
+ * @param {IGetFunctionAlias} params
1138
+ * @returns {Promise<IGetFunctionAliasRes>}
1139
+ * @memberof FunctionService
1140
+ */
1141
+ @preLazy()
1142
+ public async getFunctionAlias(params: IGetFunctionAlias): Promise<IGetFunctionAliasRes> {
1143
+ const { namespace } = this.getFunctionConfig()
1144
+ const { functionName: FunctionName, name: Name } = params
1145
+
1146
+ return this.scfService.request('GetAlias', {
1147
+ FunctionName,
1148
+ Name,
1149
+ Namespace: namespace
1150
+ })
1151
+ }
1152
+
916
1153
  @preLazy()
917
1154
  private async createAccessPath(name: string, path: string) {
918
1155
  const access = this.environment.getAccessService()
@@ -38,6 +38,10 @@ export interface IHostingFileOptions {
38
38
  onProgress?: OnProgress
39
39
  onFileFinish?: OnFileFinish
40
40
  ignore?: string | string[]
41
+ // 重试次数
42
+ retryCount?: number
43
+ // 重试时间间隔(毫秒)
44
+ retryInterval?: number
41
45
  }
42
46
 
43
47
  export interface IHostingFilesOptions {
@@ -52,6 +56,10 @@ export interface IHostingFilesOptions {
52
56
  onProgress?: OnProgress
53
57
  onFileFinish?: OnFileFinish
54
58
  ignore?: string | string[]
59
+ // 重试次数
60
+ retryCount?: number
61
+ // 重试时间间隔(毫秒)
62
+ retryInterval?: number
55
63
  }
56
64
 
57
65
  export type IHostingOptions = IHostingFileOptions | IHostingFilesOptions
@@ -331,7 +339,9 @@ export class HostingService {
331
339
  onProgress,
332
340
  onFileFinish,
333
341
  parallel = 20,
334
- ignore
342
+ ignore,
343
+ retryCount,
344
+ retryInterval
335
345
  } = options
336
346
 
337
347
  const hosting = await this.checkStatus()
@@ -355,7 +365,9 @@ export class HostingService {
355
365
  onProgress,
356
366
  onFileFinish,
357
367
  fileId: false,
358
- ignore
368
+ ignore,
369
+ retryCount,
370
+ retryInterval,
359
371
  })
360
372
  } else {
361
373
  // 文件上传统一通过批量上传接口
@@ -376,7 +388,9 @@ export class HostingService {
376
388
  bucket: Bucket,
377
389
  region: Regoin,
378
390
  files: uploadFiles,
379
- fileId: false
391
+ fileId: false,
392
+ retryCount,
393
+ retryInterval,
380
394
  })
381
395
  }
382
396
 
@@ -62,6 +62,10 @@ export interface IFilesOptions extends IOptions {
62
62
  ignore?: string | string[]
63
63
  // 文件列表
64
64
  files: { localPath: string; cloudPath?: string }[]
65
+ // 重试次数
66
+ retryCount?: number
67
+ // 重试时间间隔(毫秒)
68
+ retryInterval?: number
65
69
  }
66
70
 
67
71
  export interface ICustomOptions {
@@ -141,7 +145,8 @@ export class StorageService {
141
145
  */
142
146
  @preLazy()
143
147
  public async uploadFiles(options: IFilesOptions): Promise<void> {
144
- const { files, onProgress, parallel, onFileFinish, ignore } = options
148
+ const { files, onProgress, parallel, onFileFinish, ignore, retryCount, retryInterval } =
149
+ options
145
150
  const { bucket, region } = this.getStorageConfig()
146
151
 
147
152
  return this.uploadFilesCustom({
@@ -151,7 +156,9 @@ export class StorageService {
151
156
  ignore,
152
157
  parallel,
153
158
  onProgress,
154
- onFileFinish
159
+ onFileFinish,
160
+ retryCount,
161
+ retryInterval
155
162
  })
156
163
  }
157
164
 
@@ -403,7 +410,9 @@ export class StorageService {
403
410
  onProgress,
404
411
  onFileFinish,
405
412
  fileId = true,
406
- parallel = 20
413
+ parallel = 20,
414
+ retryCount = 0,
415
+ retryInterval = 500
407
416
  } = options
408
417
 
409
418
  if (!files || !files.length) {
@@ -445,12 +454,25 @@ export class StorageService {
445
454
 
446
455
  const cos = this.getCos(parallel)
447
456
  const uploadFiles = Util.promisify(cos.uploadFiles).bind(cos)
448
-
449
- return uploadFiles({
450
- onProgress,
451
- onFileFinish,
457
+ const params = {
452
458
  files: fileList,
453
- SliceSize: BIG_FILE_SIZE
459
+ SliceSize: BIG_FILE_SIZE,
460
+ onProgress,
461
+ onFileFinish
462
+ }
463
+
464
+ // return uploadFiles({
465
+ // onProgress,
466
+ // onFileFinish,
467
+ // files: fileList,
468
+ // SliceSize: BIG_FILE_SIZE
469
+ // })
470
+ return this.uploadFilesWithRetry({
471
+ uploadFiles,
472
+ options: params,
473
+ times: retryCount,
474
+ interval: retryInterval,
475
+ failedFiles: []
454
476
  })
455
477
  }
456
478
 
@@ -543,32 +565,42 @@ export class StorageService {
543
565
  public async downloadDirectory(options: {
544
566
  cloudPath: string
545
567
  localPath?: string
568
+ parallel?: number
546
569
  }): Promise<(NodeJS.ReadableStream | string)[]> {
547
- const { cloudPath, localPath } = options
570
+ const { cloudPath, localPath, parallel = 20 } = options
548
571
  const resolveLocalPath = path.resolve(localPath)
549
572
 
550
573
  checkFullAccess(resolveLocalPath, true)
551
574
 
552
575
  const cloudDirectoryKey = this.getCloudKey(cloudPath)
553
576
  const files = await this.walkCloudDir(cloudDirectoryKey)
554
-
555
- const promises = files.map(async file => {
556
- const fileRelativePath = file.Key.replace(cloudDirectoryKey, '')
557
- // 空路径和文件夹跳过
558
- if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
559
- return
560
- }
561
- const localFilePath = path.join(resolveLocalPath, fileRelativePath)
562
- // 创建文件的父文件夹
563
- const fileDir = path.dirname(localFilePath)
564
- await makeDir(fileDir)
565
- return this.downloadFile({
566
- cloudPath: file.Key,
567
- localPath: localFilePath
568
- })
577
+ const promises = files.map(file => async () => {
578
+ return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath })
569
579
  })
580
+ const asyncTaskController = new AsyncTaskParallelController(parallel, 50)
581
+ asyncTaskController.loadTasks(promises)
582
+ let res = await asyncTaskController.run()
583
+ const errorIndexArr = []
570
584
 
571
- return Promise.all(promises)
585
+ res.map(
586
+ (item, index) =>
587
+ /Error/gi.test(Object.prototype.toString.call(item)) && errorIndexArr.push(index)
588
+ )
589
+ // 重试逻辑
590
+ if (errorIndexArr.length) {
591
+ const errorFiles = errorIndexArr.map(errorIndex => files[errorIndex])
592
+ asyncTaskController.loadTasks(
593
+ errorFiles.map(file => async () => {
594
+ return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath })
595
+ })
596
+ )
597
+ res = await asyncTaskController.run()
598
+ }
599
+ const errorResultArr = this.determineDownLoadResultIsError(res)
600
+ if (errorResultArr.length) {
601
+ throw errorResultArr[0]
602
+ }
603
+ return res
572
604
  }
573
605
 
574
606
  /**
@@ -1068,7 +1100,6 @@ export class StorageService {
1068
1100
  }
1069
1101
  }
1070
1102
 
1071
- console.log('params:', JSON.stringify(params))
1072
1103
  const res = await putBucketWebsite(params)
1073
1104
 
1074
1105
  return res
@@ -1165,37 +1196,86 @@ export class StorageService {
1165
1196
  * @returns
1166
1197
  */
1167
1198
  private async uploadFilesWithRetry({ uploadFiles, options, times, interval, failedFiles }) {
1168
- console.log('times', times)
1169
1199
  const { files, onFileFinish } = options
1170
1200
  const tempFailedFiles = []
1201
+ let curError: any = null
1171
1202
  const res = await uploadFiles({
1172
1203
  ...options,
1173
1204
  files: failedFiles.length
1174
1205
  ? files.filter(file => failedFiles.includes(file.Key))
1175
1206
  : files,
1176
1207
  onFileFinish: (...args) => {
1177
- console.log('args', args)
1178
1208
  const error = args[0]
1179
1209
  const fileInfo = (args as any)[2]
1180
1210
  if (error) {
1211
+ curError = error
1181
1212
  tempFailedFiles.push(fileInfo.Key)
1182
1213
  }
1183
1214
  onFileFinish?.apply(null, args)
1184
1215
  }
1185
1216
  })
1186
- if (!tempFailedFiles?.length || times <= 0) return res
1187
- if (times > 0) {
1188
- setTimeout(
1189
- () =>
1190
- this.uploadFilesWithRetry({
1191
- uploadFiles,
1192
- options,
1193
- times: times - 1,
1194
- interval,
1195
- failedFiles: tempFailedFiles
1196
- }),
1197
- interval
1198
- )
1217
+ // if (!tempFailedFiles?.length || times <= 0) return res
1218
+
1219
+ if (!tempFailedFiles?.length) {
1220
+ return res
1221
+ } else {
1222
+ if (times > 0) {
1223
+ return await new Promise((resolve, reject) => {
1224
+ setTimeout(
1225
+ () =>
1226
+ this.uploadFilesWithRetry({
1227
+ uploadFiles,
1228
+ options,
1229
+ times: times - 1,
1230
+ interval,
1231
+ failedFiles: tempFailedFiles
1232
+ }).then(res => resolve(res))
1233
+ .catch(err => reject(err)),
1234
+ interval
1235
+ )
1236
+ })
1237
+ } else {
1238
+ if (curError) {
1239
+ throw curError
1240
+ }
1241
+ }
1199
1242
  }
1200
1243
  }
1244
+
1245
+ /**
1246
+ * 拼接路径下载单文件
1247
+ * @param file
1248
+ * @param cloudDirectoryKey
1249
+ * @param resolveLocalPath
1250
+ * @returns
1251
+ */
1252
+ private async downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath }) {
1253
+ const fileRelativePath = file.Key.replace(cloudDirectoryKey, '')
1254
+ // 空路径和文件夹跳过
1255
+ if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
1256
+ return
1257
+ }
1258
+ const localFilePath = path.join(resolveLocalPath, fileRelativePath)
1259
+ // 创建文件的父文件夹
1260
+ const fileDir = path.dirname(localFilePath)
1261
+ await makeDir(fileDir)
1262
+ return this.downloadFile({
1263
+ cloudPath: file.Key,
1264
+ localPath: localFilePath
1265
+ })
1266
+ }
1267
+
1268
+ /**
1269
+ * 根据下载结果返回错误列表
1270
+ * @param res
1271
+ * @returns
1272
+ */
1273
+ private determineDownLoadResultIsError(res) {
1274
+ const resultErrorArr = []
1275
+ res.map(
1276
+ item =>
1277
+ /Error/gi.test(Object.prototype.toString.call(item)) && resultErrorArr.push(item)
1278
+ )
1279
+ return resultErrorArr
1280
+ }
1201
1281
  }
@@ -87,6 +87,92 @@ export interface IGetLayerVersionRes extends IResponseInfo {
87
87
  LayerName: string;
88
88
  Status: string;
89
89
  }
90
+ export interface ISetProvisionedConcurrencyConfig {
91
+ functionName: string;
92
+ qualifier: string;
93
+ versionProvisionedConcurrencyNum: number;
94
+ }
95
+ export interface IGetProvisionedConcurrencyConfig {
96
+ functionName: string;
97
+ qualifier?: string;
98
+ }
99
+ export interface IVersionProvisionedConcurrencyInfo {
100
+ AllocatedProvisionedConcurrencyNum: number;
101
+ AvailableProvisionedConcurrencyNum: number;
102
+ Status: string;
103
+ StatusReason: string;
104
+ Qualifier: string;
105
+ }
106
+ export interface IGetProvisionedConcurrencyRes extends IResponseInfo {
107
+ UnallocatedConcurrencyNum: number;
108
+ Allocated: IVersionProvisionedConcurrencyInfo[];
109
+ }
110
+ export interface IPublishVersionParams {
111
+ functionName: string;
112
+ description?: string;
113
+ }
114
+ export interface IPublishVersionRes extends IResponseInfo {
115
+ FunctionVersion: string;
116
+ CodeSize: number;
117
+ MemorySize: number;
118
+ Description: string;
119
+ Handler: string;
120
+ Timeout: number;
121
+ Runtime: string;
122
+ Namespace: string;
123
+ }
124
+ export interface IListFunctionVersionParams {
125
+ functionName: string;
126
+ offset?: number;
127
+ limit?: number;
128
+ order?: string;
129
+ orderBy?: string;
130
+ }
131
+ export interface IFunctionVersion {
132
+ Version: string;
133
+ Description: string;
134
+ AddTime: string;
135
+ ModTime: string;
136
+ Status: string;
137
+ }
138
+ export interface IFunctionVersionsRes extends IResponseInfo {
139
+ FunctionVersion: string[];
140
+ Versions: IFunctionVersion[];
141
+ TotalCount: number;
142
+ }
143
+ export interface IVersionMatch {
144
+ Version: string;
145
+ Key: string;
146
+ Method: string;
147
+ Expression: string;
148
+ }
149
+ export interface IVersionWeight {
150
+ Version: string;
151
+ Weight: number;
152
+ }
153
+ export interface IRoutingConfig {
154
+ AdditionalVersionWeights?: IVersionWeight[];
155
+ AddtionVersionMatchs?: IVersionMatch[];
156
+ }
157
+ export interface IUpdateFunctionAliasConfig {
158
+ functionName: string;
159
+ name: string;
160
+ functionVersion: string;
161
+ description?: string;
162
+ routingConfig?: IRoutingConfig;
163
+ }
164
+ export interface IGetFunctionAlias {
165
+ functionName: string;
166
+ name: string;
167
+ }
168
+ export interface IGetFunctionAliasRes extends IResponseInfo {
169
+ FunctionVersion: string;
170
+ Name: string;
171
+ RoutingConfig: IRoutingConfig;
172
+ Description: string;
173
+ AddTime: string;
174
+ ModTime: string;
175
+ }
90
176
  export declare class FunctionService {
91
177
  private environment;
92
178
  private vpcService;
@@ -210,6 +296,58 @@ export declare class FunctionService {
210
296
  listLayerVersions(options: IVersionListOptions): Promise<IListLayerVersionsRes>;
211
297
  listLayers(options: ILayerListOptions): Promise<IListLayerRes>;
212
298
  getLayerVersion(options: ILayerOptions): Promise<IGetLayerVersionRes>;
299
+ /**
300
+ * 设置预置并发
301
+ * @private
302
+ * @param {IProvisionedConcurrencyConfig} concurrencyConfig
303
+ * @returns
304
+ * @memberof FunctionService
305
+ */
306
+ setProvisionedConcurrencyConfig(concurrencyConfig: ISetProvisionedConcurrencyConfig): Promise<IResponseInfo>;
307
+ /**
308
+ * 获取函数预置并发详情
309
+ * @private
310
+ * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
311
+ * @returns {Promise<IGetProvisionedConcurrencyRes>}
312
+ * @memberof FunctionService
313
+ */
314
+ getProvisionedConcurrencyConfig(concurrencyConfig: IGetProvisionedConcurrencyConfig): Promise<IGetProvisionedConcurrencyRes>;
315
+ /**
316
+ * 删除预置并发
317
+ * @private
318
+ * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
319
+ * @returns {Promise<IResponseInfo>}
320
+ * @memberof FunctionService
321
+ */
322
+ deleteProvisionedConcurrencyConfig(concurrencyConfig: IGetProvisionedConcurrencyConfig): Promise<IResponseInfo>;
323
+ /**
324
+ * 发布新版本
325
+ * @param {IPublishVersionParams} publishParams
326
+ * @returns {Promise<IPublishVersionRes>}
327
+ * @memberof FunctionService
328
+ */
329
+ publishVersion(publishParams: IPublishVersionParams): Promise<IPublishVersionRes>;
330
+ /**
331
+ * 查询函数版本详情
332
+ * @param {IListFunctionVersionParams} listVersionParams
333
+ * @returns {Promise<IFunctionVersionsRes>}
334
+ * @memberof FunctionService
335
+ */
336
+ listVersionByFunction(listVersionParams: IListFunctionVersionParams): Promise<IFunctionVersionsRes>;
337
+ /**
338
+ *
339
+ * @param {IUpdateFunctionAliasConfig} updateVersionConfigParams
340
+ * @returns {Promise<IResponseInfo>}
341
+ * @memberof FunctionService
342
+ */
343
+ updateFunctionAliasConfig(updateVersionConfigParams: IUpdateFunctionAliasConfig): Promise<IResponseInfo>;
344
+ /**
345
+ * 查询函数别名详情
346
+ * @param {IGetFunctionAlias} params
347
+ * @returns {Promise<IGetFunctionAliasRes>}
348
+ * @memberof FunctionService
349
+ */
350
+ getFunctionAlias(params: IGetFunctionAlias): Promise<IGetFunctionAliasRes>;
213
351
  private createAccessPath;
214
352
  private getCodeParams;
215
353
  private getTempCosInfo;
@@ -20,6 +20,8 @@ export interface IHostingFileOptions {
20
20
  onProgress?: OnProgress;
21
21
  onFileFinish?: OnFileFinish;
22
22
  ignore?: string | string[];
23
+ retryCount?: number;
24
+ retryInterval?: number;
23
25
  }
24
26
  export interface IHostingFilesOptions {
25
27
  localPath?: string;
@@ -32,6 +34,8 @@ export interface IHostingFilesOptions {
32
34
  onProgress?: OnProgress;
33
35
  onFileFinish?: OnFileFinish;
34
36
  ignore?: string | string[];
37
+ retryCount?: number;
38
+ retryInterval?: number;
35
39
  }
36
40
  export declare type IHostingOptions = IHostingFileOptions | IHostingFilesOptions;
37
41
  export interface IHostingCloudOptions {
@@ -27,6 +27,8 @@ export interface IFilesOptions extends IOptions {
27
27
  localPath: string;
28
28
  cloudPath?: string;
29
29
  }[];
30
+ retryCount?: number;
31
+ retryInterval?: number;
30
32
  }
31
33
  export interface ICustomOptions {
32
34
  bucket: string;
@@ -149,6 +151,7 @@ export declare class StorageService {
149
151
  downloadDirectory(options: {
150
152
  cloudPath: string;
151
153
  localPath?: string;
154
+ parallel?: number;
152
155
  }): Promise<(NodeJS.ReadableStream | string)[]>;
153
156
  /**
154
157
  * 列出文件夹下的文件
@@ -303,5 +306,19 @@ export declare class StorageService {
303
306
  * @returns
304
307
  */
305
308
  private uploadFilesWithRetry;
309
+ /**
310
+ * 拼接路径下载单文件
311
+ * @param file
312
+ * @param cloudDirectoryKey
313
+ * @param resolveLocalPath
314
+ * @returns
315
+ */
316
+ private downloadWithFilePath;
317
+ /**
318
+ * 根据下载结果返回错误列表
319
+ * @param res
320
+ * @returns
321
+ */
322
+ private determineDownLoadResultIsError;
306
323
  }
307
324
  export {};