This repository has been archived by the owner on Jul 2, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: single process invoke and debug (#16)
* fix: use single process invoke * feat: single process invoke * fix: new invoke debug
- Loading branch information
1 parent
3c18e50
commit 826a8c7
Showing
29 changed files
with
441 additions
and
432 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,3 +22,5 @@ export class ApiGatewayTrigger extends FCBaseTrigger { | |
} | ||
|
||
} | ||
|
||
export const apigw = ApiGatewayTrigger; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,3 +38,5 @@ export class CDNTrigger extends FCBaseTrigger { | |
} | ||
|
||
} | ||
|
||
export const cdn = CDNTrigger; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,3 +49,5 @@ export class OSSTrigger extends FCBaseTrigger { | |
} | ||
|
||
} | ||
|
||
export const oss = OSSTrigger; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,3 +27,5 @@ export class SLSTrigger extends FCBaseTrigger { | |
} | ||
|
||
} | ||
|
||
export const sls = SLSTrigger; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,3 +17,4 @@ export class TimerTrigger extends FCBaseTrigger { | |
} | ||
|
||
} | ||
export const timer = TimerTrigger; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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。 | ||
` : ''} | ||
*/`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
})(); |
Oops, something went wrong.