Skip to content
This repository has been archived by the owner on Jul 2, 2020. It is now read-only.

Commit

Permalink
feat: single process invoke and debug (#16)
Browse files Browse the repository at this point in the history
* fix: use single process invoke
* feat: single process invoke
* fix: new invoke debug
  • Loading branch information
echosoar authored and czy88840616 committed Jan 9, 2020
1 parent 3c18e50 commit 826a8c7
Show file tree
Hide file tree
Showing 29 changed files with 441 additions and 432 deletions.
1 change: 1 addition & 0 deletions packages/faas-cli-plugin-fc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"@alicloud/fun": "^3.1.3",
"@midwayjs/fcli-command-core": "^0.2.2",
"@midwayjs/serverless-spec-builder": "^0.2.2",
"@midwayjs/serverless-fc-starter": "^0.2.0",
"ejs": "^3.0.1"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/faas-cli-plugin-fc/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { homedir } from 'os';
import { writeFileSync, existsSync } from 'fs';
import { render } from 'ejs';
import { generateFunctionsSpecFile } from '@midwayjs/serverless-spec-builder/fc';
import { wrapperContent } from './wrapper';
import { wrapperContent } from '@midwayjs/serverless-fc-starter';
import { formatLayers } from './utils';
export class AliyunFCPlugin extends BasePlugin {
core: ICoreInstance;
Expand Down
35 changes: 1 addition & 34 deletions packages/faas-cli-plugin-invoke/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,47 +44,14 @@ export class InvokePlugin extends BasePlugin {
async invokeFun(functionName: string) {
const allFunctions = this.core.service.functions || {};
const funcConf = allFunctions[functionName];
const layersList = [{}, this.core.service.layers || {}];
const providerName =
this.core.service.provider && this.core.service.provider.name;
let eventResult = [];
if (funcConf) {
const events = funcConf.events;
if (Array.isArray(events)) {
let eventKey = [];
for (const evt of events) {
eventKey = eventKey.concat(Object.keys(evt));
}
eventResult = eventKey;
}
}

const layers = Object.assign.apply({}, layersList);

const eventOptions =
this.getEventOptions(
providerName,
this.options.event || this.options.trigger || eventResult[0]
) || {};

const options = {
functionDir: this.core.config.servicePath,
functionName,
debug: this.options.debug,
data: this.options.data || '{}',
handler: funcConf.handler,
layers,
...eventOptions,
handler: funcConf.handler
};
return invoke(options);
}

// 获取触发器及starter配置
getEventOptions(providerName?: string, eventName?: string) {
return {
starter: '',
eventPath: '',
eventName: '',
};
}
}
2 changes: 1 addition & 1 deletion packages/faas-cli-plugin-package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"archiver": "^3.1.1",
"fs-extra": "^8.1.0",
"globby": "^10.0.1",
"midway-bin": "^1.15.1"
"midway-bin": "1"
},
"files": [
"src",
Expand Down
1 change: 1 addition & 0 deletions packages/serverless-fc-starter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FCRuntime } from './runtime';

export { asyncWrapper } from '@midwayjs/runtime-engine';
export * from './runtime';
export * from './wrapper';

let bootstrap;

Expand Down
2 changes: 2 additions & 0 deletions packages/serverless-fc-trigger/src/apiGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ export class ApiGatewayTrigger extends FCBaseTrigger {
}

}

export const apigw = ApiGatewayTrigger;
2 changes: 2 additions & 0 deletions packages/serverless-fc-trigger/src/cdn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ export class CDNTrigger extends FCBaseTrigger {
}

}

export const cdn = CDNTrigger;
6 changes: 4 additions & 2 deletions packages/serverless-fc-trigger/src/http.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { exec } from 'child_process';
import * as express from 'express';
import * as http from 'http';
import * as HTTP from 'http';
import { FCBaseTrigger } from './base';

interface HTTPTriggerOpts {
Expand Down Expand Up @@ -44,7 +44,7 @@ export class HTTPTrigger extends FCBaseTrigger {
return new Promise((resolve, reject) => {
if (!this.httpServer) {
const app = express();
this.httpServer = http.createServer(app);
this.httpServer = HTTP.createServer(app);

app.get('*', (req, res, next) => {
/**
Expand Down Expand Up @@ -184,3 +184,5 @@ class Response {
};
}
}

export const http = HTTPTrigger;
2 changes: 2 additions & 0 deletions packages/serverless-fc-trigger/src/oss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ export class OSSTrigger extends FCBaseTrigger {
}

}

export const oss = OSSTrigger;
2 changes: 2 additions & 0 deletions packages/serverless-fc-trigger/src/sls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export class SLSTrigger extends FCBaseTrigger {
}

}

export const sls = SLSTrigger;
1 change: 1 addition & 0 deletions packages/serverless-fc-trigger/src/timer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export class TimerTrigger extends FCBaseTrigger {
}

}
export const timer = TimerTrigger;
2 changes: 2 additions & 0 deletions packages/serverless-invoke/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
"dependencies": {
"@midwayjs/fcli-command-core": "^0.2.2",
"@midwayjs/runtime-mock": "^0.2.0",
"@midwayjs/runtime-engine": "^0.2.0",
"@midwayjs/serverless-fc-starter": "^0.2.0",
"@midwayjs/serverless-fc-trigger": "^0.2.0",
"@midwayjs/serverless-scf-starter": "^0.2.0",
"@midwayjs/serverless-scf-trigger": "^0.2.0",
"fs-extra": "^8.1.0",
"ts-node": "^8.5.2",
"urllib": "^2.34.1",
"websocket": "^1.0.30"
Expand Down
221 changes: 221 additions & 0 deletions packages/serverless-invoke/src/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
单进程模式的invoke
invoke -> (trigger)-> invokeCore -> entrence -> userCode[ts build]
1. 用户调用invoke
2. tsc编译用户代码到dist目录
3. 开源版: 【创建runtime、创建trigger】封装为平台invoke包,提供getInvoke方法,会传入args与入口方法,返回invoke方法
*/
import { FaaSStarterClass } from './utils';
import { execSync } from 'child_process';
import { resolve } from 'path';
import { existsSync, writeFileSync, ensureDirSync } from 'fs-extra';
import { loadSpec } from '@midwayjs/fcli-command-core';
import { render } from 'ejs';

interface InvokeOptions {
baseDir?: string; // 目录,默认为process.cwd
functionName: string; // 函数名
isDebug?: boolean; // 是否debug
handler?: string; // 函数的handler方法
trigger?: string; // 触发器
buildDir?: string; // 构建目录
}

export class InvokeCore {
options: InvokeOptions;
baseDir: string;
starter: any;
spec: any;
buildDir: string;
wrapperInfo: any;

constructor(options: InvokeOptions) {
this.options = options;
this.baseDir = options.baseDir || process.cwd();
this.buildDir = resolve(this.baseDir, options.buildDir || 'dist');
ensureDirSync(this.buildDir);
this.spec = loadSpec(this.baseDir);
}

async getStarter() {
if (this.starter) {
return this.starter;
}
const { functionName } = this.options;
const starter = new FaaSStarterClass({
baseDir: this.buildDir,
functionName
});
await starter.start();
this.starter = starter;
return this.starter;
}

// 获取用户代码中的函数方法
async getUserFaasHandlerFunction() {
const handler = this.options.handler || this.getFunctionInfo().handler || '';
const starter = await this.getStarter();
return starter.handleInvokeWrapper(handler);
}

getFunctionInfo(functionName?: string) {
functionName = functionName || this.options.functionName;
return this.spec && this.spec.functions && this.spec.functions[functionName] || {};
}

async getInvokeFunction() {
const invoke = await this.getUserFaasHandlerFunction();
return invoke;
}

async buildTS() {
const { baseDir } = this.options;
process.env.MIDWAY_TS_MODE = 'true';
const tsconfig = resolve(baseDir, 'tsconfig.json');
// 非ts
if (!existsSync(tsconfig)) {
return;
}
const distTsconfig = resolve(this.buildDir, 'tsconfig.json');
if (!existsSync(distTsconfig)) { // midway-core 扫描判断isTsMode需要
writeFileSync(distTsconfig, '{}');
}
let tsc = 'tsc';
const tscBuildDir = resolve(this.buildDir, 'src');
try {
tsc = resolve(require.resolve('typescript'), '../../bin/tsc');
} catch (e) {
return this.invokeError('need typescript');
}
try {
await execSync(`cd ${baseDir};${tsc} --inlineSourceMap --outDir ${tscBuildDir} --skipLibCheck --skipDefaultLibCheck`);
} catch (e) {
this.invokeError(e);
}
}

async invoke(...args: any) {
await this.buildTS();
const invoke = await this.getInvokeFunction();
this.checkDebug();
return invoke(...args);
}

async invokeError(err) {
console.log('[faas invoke error]');
console.log(err);
process.exit(1);
}

async loadHandler(WrapperContent: string) {
const wrapperInfo = await this.makeWrapper(WrapperContent);
const { fileName, handlerName } = wrapperInfo;
this.wrapperInfo = wrapperInfo;
try {
const handler = require(fileName);
return handler[handlerName];
} catch (e) {
this.invokeError(e);
}
}

// 写入口
async makeWrapper(WrapperContent: string) {
const funcInfo = this.getFunctionInfo();
const [handlerFileName, name] = funcInfo.handler.split('.');
const funcLayers = funcInfo.layers || [];
const handlers = [];

// 高密度部署
if (funcInfo._isAggregation && funcInfo.functions) {
handlers.push({
name,
handlers: funcInfo._handlers,
});
} else {
handlers.push({
name,
handler: funcInfo.handler,
});
}

const fileName = resolve(this.buildDir, `${handlerFileName}.js`);
const layers = this.getLayers(
this.spec.layers,
...funcLayers
);
const content = render(WrapperContent, {
handlers,
...layers,
});
writeFileSync(fileName, content);
return { fileName, handlerName: name };
}

// 安装layer
private getLayers(...layersList: any) {
const layerTypeList = this.formatLayers(...layersList);
const layerDeps = [];
const layers = [];

if (layerTypeList && layerTypeList.npm) {
Object.keys(layerTypeList.npm).forEach((originName: string) => {
const name = 'layer_' + originName;
layerDeps.push({ name, path: layerTypeList.npm[originName] });
layers.push(name);
});
}
return {
layerDeps,
layers,
};
}

// 格式化layers
formatLayers(...multiLayers: any[]) {
const layerTypeList = { npm: {} };
multiLayers.forEach((layer: any) => {
Object.keys(layer || {}).forEach(layerName => {
const [type, path] = layer[layerName].path.split(':');
if (!layerTypeList[type]) {
return;
}
layerTypeList[type][layerName] = path;
});
});
return layerTypeList;
}

wrapperHandler(handler) {
return handler;
}

checkDebug() {
if (!this.options.isDebug) {
return;
}
// tslint:disable-next-line: no-eval
eval(`
debugger;
/*
Debug 温馨提示
请点击左侧文件目录中的代码文件进行调试
${this.wrapperInfo ? `
函数的入口文件所在:
${this.wrapperInfo.fileName}
其中 exports.${this.wrapperInfo.handlerName} 方法为函数入口。
请断点至此函数
执行至此函数时,会自动生成源代码 sourceMap,方可继续调试。
感谢使用 midway-faas。
` : ''}
*/`);
}
}
23 changes: 18 additions & 5 deletions packages/serverless-invoke/src/debug.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
export const faasDebug = faasHandle => {
// 下一步将进入函数
// faasHandler 为函数的 handle方法
return faasHandle();
};
import { invoke } from './main';
import { send, waitDebug } from './utils';
const [parentOptions, debugPort] = process.argv.slice(2);
let options: any = {};
try {
options = JSON.parse(parentOptions);
delete options.debug;
} catch (e) {}
(async () => {
try {
await waitDebug(debugPort);
const resultData = await invoke(options);
send('faastest', resultData);
} catch (e) {
send('faastest', 'error: ' + e.message);
}
process.exit();
})();

0 comments on commit 826a8c7

Please sign in to comment.