Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {
} from './lib/profile';
import { IProperties, IInputs } from './interface';
import * as path from 'path';
import { formatArgs, hasHttpPrefix } from './lib/utils/utils';
import { promiseRetry, retryDeployUntilSlsCreated } from './lib/retry';
import { formatArgs, hasHttpPrefix, isDeployFunctionErrorAcrNotExist } from './lib/utils/utils';
import { promiseRetry, retryDeployFunctionErrorAcrNotExist, retryDeployUntilSlsCreated } from './lib/retry';
import { isSlsNotExistException } from './lib/error';
import StdoutFormatter from './lib/component/stdout-formatter';
import { isAutoConfig } from './lib/definition';
Expand Down Expand Up @@ -932,18 +932,27 @@ export default class FcDeployComponent {
}
return;
} catch (ex) {
logger.debug(
`error when create service/function/trigger or update service/function/trigger, error is: \n${ex}`,
);

// 需要 retry 镜像,并且报错中含有下面信息的 retry 3min, 如果还报错则跳出循环
if (isDeployFunctionErrorAcrNotExist(ex.message) && this.fcFunction.retryErrorAcrNotExist) {
logger.debug('Need to retry deploy function');
await retryDeployFunctionErrorAcrNotExist(fcBaseComponentIns, fcBaseComponentInputs);
retry(ex);
}
// 代码包问题给出方案跳出
if (/^the size of file \d+ could not greater than \d+$/.test(ex.message)) {
throw new core.CatchableError(
ex.message,
'For large code package upload, please refer to https://github.com/awesome-fc/fc-faq/blob/main/docs/大代码包部署的实践案例.md',
);
}
// 权限问题或者日志 auto 的问题直接跳出
if (ex.code === 'AccessDenied' || (logConfigIsAuto && isSlsNotExistException(ex))) {
throw ex;
}
logger.debug(
`error when create service/function/trigger or update service/function/trigger, error is: \n${ex}`,
);
logger.debug(StdoutFormatter.stdoutFormatter.retry('fc', 'create', '', times));
retry(ex);
}
Expand Down
12 changes: 7 additions & 5 deletions src/lib/fc/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export class FcFunction extends FcDeploy<FunctionConfig> {
readonly name: string;
originalCodeUri: string; // build 场景下赋值
isBuild = false; // 是否执行了 build
retryErrorAcrNotExist: boolean; // 是否需要 retry 函数错误:ARTIFACT_NOT_EXIST

static readonly DEFAULT_BUILD_ARTIFACTS_PATH_SUFFIX: string = path.join(
'.s',
Expand Down Expand Up @@ -289,7 +290,7 @@ export class FcFunction extends FcDeploy<FunctionConfig> {
const imageRegistry: string = AlicloudAcr.extractRegistryFromAcrUrl(
this.localConfig?.customContainerConfig?.image,
);
if (AlicloudAcr.isAciRegistry(imageRegistry)) {
if (AlicloudAcr.isAcreeRegistry(imageRegistry)) {
if (!this.localConfig?.customContainerConfig?.instanceID) {
throw new core.CatchableError('When an enterprise version instance is selected for the container image, you need to add an instance ID to the enterprise version of the container image service. Refer to: https://docs.serverless-devs.com/fc/yaml/function#customcontainerconfig');
}
Expand Down Expand Up @@ -569,8 +570,9 @@ export class FcFunction extends FcDeploy<FunctionConfig> {
return true;
}
if (!(await imageExist(this.localConfig.customContainerConfig.image))) {
this.logger.info(
`\nImage ${this.localConfig.customContainerConfig.image} does not exist locally.\nMaybe you need to run 's build' first if it does not exist remotely.`,
this.logger.log(
`\nImage ${this.localConfig.customContainerConfig.image} dose not exist locally.\nMaybe you need to run 's build' first if it dose not exist remotely.`,
'red',
);
return false;
}
Expand All @@ -594,7 +596,7 @@ export class FcFunction extends FcDeploy<FunctionConfig> {
this.region,
);
const { image, instanceID } = this.localConfig?.customContainerConfig || {};
await alicloudAcr.pushImage(image, instanceID, assumeYes);
this.retryErrorAcrNotExist = await alicloudAcr.pushImage(image, instanceID, assumeYes);
}
} catch (e) {
handleKnownErrors(e);
Expand Down Expand Up @@ -647,7 +649,7 @@ export class FcFunction extends FcDeploy<FunctionConfig> {
}
// upload code to oss
const defaultObjectName = `fcComponentGeneratedDir/${this.serviceName}-${this.name
}-${zipCodeFileHash.substring(0, 5)}`;
}-${zipCodeFileHash.substring(0, 5)}`;
const uploadVm = core.spinner(
`Uploading zipped code: ${zipCodeFilePath} to oss://${this.localConfig?.ossBucket}/${defaultObjectName}`,
);
Expand Down
25 changes: 18 additions & 7 deletions src/lib/resource/acr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,17 @@ export class AlicloudAcr extends AlicloudClient {
}
}

async pushImage(image: string, instanceID?: string, assumeYes?: boolean): Promise<void> {
async pushImage(imageConfig: string, instanceID?: string, assumeYes?: boolean): Promise<boolean> {
// 如果是加速镜像则转换成非加速镜像
let image = imageConfig;
let retryErrorAcrNotExist = false;
if (instanceID && _.endsWith(image, '_accelerated')) {
logger.debug(`Image is acree and ends with _accelerated, transfrom image: ${image}`);
image = _.trimEnd(image, '_accelerated');
logger.debug(`To image is: ${image}`);
retryErrorAcrNotExist = true;
}

const imageArr = image.split('/');
if (this.pushRegistry === 'acr-vpc') {
imageArr[0] = AlicloudAcr.internetImageToVpcImage(this.region, imageArr[0]);
Expand Down Expand Up @@ -188,7 +198,7 @@ export class AlicloudAcr extends AlicloudClient {
try {
this.logger.log(`Pushing docker image: ${image}...`, 'yellow');
execSync(`docker push ${image}`, { stdio: 'inherit' });
return;
return retryErrorAcrNotExist;
} catch (e) {
if (image === resolvedImage) {
throw e;
Expand All @@ -197,23 +207,24 @@ export class AlicloudAcr extends AlicloudClient {
this.logger.debug(`Push image: ${image} failed, error is ${e}`);
}

const tagVm = core.spinner(`Tagging image ${image} as ${resolvedImage}\t`);
const tagVm = core.spinner(`Tagging image ${imageConfig} as ${resolvedImage}\t`);
try {
execSync(`docker tag ${image} ${resolvedImage}`, { stdio: 'inherit' });
tagVm.succeed(`Tag image ${image} as ${resolvedImage}\t`);
execSync(`docker tag ${imageConfig} ${resolvedImage}`, { stdio: 'inherit' });
tagVm.succeed(`Tag image ${imageConfig} as ${resolvedImage}\t`);
} catch (e) {
tagVm.fail(`Tag image ${image} as ${resolvedImage} failed.\t`);
tagVm.fail(`Tag image ${imageConfig} as ${resolvedImage} failed.\t`);
throw e;
}

this.logger.log(`Pushing docker image: ${resolvedImage}...`, 'yellow');
execSync(`docker push ${resolvedImage}`, { stdio: 'inherit' });
return retryErrorAcrNotExist;
}

static isAcrRegistry(registry: string): boolean {
return registry.startsWith('registry') && registry.endsWith('.aliyuncs.com');
}
static isAciRegistry(registry: string): boolean { // 容器镜像企业服务
static isAcreeRegistry(registry: string): boolean { // 容器镜像企业服务
return registry.includes('registry') && registry.endsWith('cr.aliyuncs.com');
}
static extractRegionFromAcrRegistry(registry: string): string {
Expand Down
29 changes: 25 additions & 4 deletions src/lib/retry.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
'use strict';

import { lodash } from '@serverless-devs/core';
import retry from 'promise-retry';
import { isSlsNotExistException } from './error';
import { sleep } from './utils/time';
import logger from '../common/logger';
import { isDeployFunctionErrorAcrNotExist } from './utils/utils';

const defaultRetries = 2;

export async function promiseRetry(fn: any): Promise<any> {
const retryOptions = {
export async function promiseRetry(fn: any, retryOptions?): Promise<any> {
return retry(fn, lodash.defaults(retryOptions, {
retries: defaultRetries,
factor: 2,
minTimeout: 1 * 1000,
randomize: true,
};
return retry(fn, retryOptions);
}));
}

export async function retryDeployFunctionErrorAcrNotExist(
componentInstance: any,
componentInputs: any,
retryTimes = 36,
) {
let slsRetry = 0;
do {
try {
await componentInstance.deploy(componentInputs);
return;
} catch (e) {
if (!isDeployFunctionErrorAcrNotExist(e.message)) {
return;
}
slsRetry++;
await sleep(5000);
}
} while (slsRetry < retryTimes);
}

export async function retryDeployUntilSlsCreated(
Expand Down
3 changes: 3 additions & 0 deletions src/lib/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,6 @@ export function objectDeepTransfromString(source) {

return source;
}


export const isDeployFunctionErrorAcrNotExist = (message: string) => _.includes(message, 'ErrorMessage: Repo artifact is not exist. , ErrorCode: ARTIFACT_NOT_EXIST;');