diff --git a/docker-compose.yml b/docker-compose.yml index 8a324be43f..810586750a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -54,16 +54,16 @@ services: SYS_SERVER_SECRET_SALT: Rewrite_Your_Own_Secret_Salt_abcdefg1234567 SHARED_NETWORK: laf_shared_network LOG_LEVEL: debug - APP_SERVICE_IMAGE: lafyun/app-service:0.6.5 + APP_SERVICE_IMAGE: lafyun/app-service:latest ACCOUNT_DEFAULT_APP_QUOTA: 5 APP_SERVICE_DEPLOY_HOST: local-dev.host:8080 # `*.local-dev.host` always resolved to 127.0.0.1, used to local development APP_SERVICE_DEPLOY_URL_SCHEMA: 'http' - DEBUG_BIND_HOST_APP_PATH: '${PWD}/packages/app-service' + # DEBUG_BIND_HOST_APP_PATH: '${PWD}/packages/app-service' command: npx nodemon volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./packages/system-server:/app - - ./packages/cloud-function-engine:/app/node_modules/cloud-function-engine:ro + - ./packages/cloud-function:/app/node_modules/cloud-function-engine:ro - ./packages/database-proxy:/app/node_modules/database-proxy:ro - ./packages/database-ql:/app/node_modules/database-ql:ro - ./packages/database-ql:/app/node_modules/database-proxy/node_modules/database-ql:ro diff --git a/packages/app-service/src/api/function-log.ts b/packages/app-service/src/api/function-log.ts index e3b96b2c1a..da0a8fd1be 100644 --- a/packages/app-service/src/api/function-log.ts +++ b/packages/app-service/src/api/function-log.ts @@ -1,7 +1,7 @@ /* * @Author: Maslow * @Date: 2021-07-30 10:30:29 - * @LastEditTime: 2021-10-06 19:21:13 + * @LastEditTime: 2021-11-03 16:45:06 * @Description: */ import { Constants } from "../constants" @@ -18,7 +18,10 @@ export async function addFunctionLog(data: any): Promise { if (!data) return null const r = await db.collection(Constants.function_log_collection) - .insertOne(data) + .insertOne({ + ...data, + created_at: new Date() + }) return r.insertedId } \ No newline at end of file diff --git a/packages/app-service/src/api/indexes.ts b/packages/app-service/src/api/indexes.ts new file mode 100644 index 0000000000..72d708ed37 --- /dev/null +++ b/packages/app-service/src/api/indexes.ts @@ -0,0 +1,31 @@ +/* + * @Author: Maslow + * @Date: 2021-07-30 10:30:29 + * @LastEditTime: 2021-11-03 17:06:38 + * @Description: + */ +import Config from "../config" +import { Constants } from "../constants" +import { DatabaseAgent } from "../lib/database" + +/** + * Add function execution log + * @param data + * @returns + */ +export async function ensureCollectionIndexes(): Promise { + const db = DatabaseAgent.db + await db.collection(Constants.function_log_collection) + .createIndexes([ + { + key: { created_at: 1 }, + expireAfterSeconds: Config.FUNCTION_LOG_EXPIRED_TIME + }, + { + key: { requestId: 1 } + }, + { key: { func_id: 1 } } + ]) + + return true +} \ No newline at end of file diff --git a/packages/app-service/src/cloud-sdk/README.md b/packages/app-service/src/cloud-sdk/README.md index 300f4fbe87..475edf2748 100644 --- a/packages/app-service/src/cloud-sdk/README.md +++ b/packages/app-service/src/cloud-sdk/README.md @@ -1,6 +1,6 @@ -> cloud-sdk 是用于云函数中,做为云函数的 SDK 使用,暴露 less-framework 中的一些资源对象。 +> cloud-sdk 是用于云函数中,做为云函数的 SDK 使用,暴露 LaF 中的一些资源对象。 在云函数中使用示例: diff --git a/packages/app-service/src/cloud-sdk/index.ts b/packages/app-service/src/cloud-sdk/index.ts index d19f585eb4..efa0bc53fe 100644 --- a/packages/app-service/src/cloud-sdk/index.ts +++ b/packages/app-service/src/cloud-sdk/index.ts @@ -34,7 +34,7 @@ export interface CloudSdkInterface { storage(bucket?: string): FileStorageInterface /** - * 获取 less api database ORM 实例 + * 获取 LaF database 实例 */ database(): Db, diff --git a/packages/app-service/src/cloud-sdk/invoke.ts b/packages/app-service/src/cloud-sdk/invoke.ts index fdf5795dcd..19a1b6df41 100644 --- a/packages/app-service/src/cloud-sdk/invoke.ts +++ b/packages/app-service/src/cloud-sdk/invoke.ts @@ -1,5 +1,6 @@ import { getFunctionByName } from "../api/function" import { CloudFunction, FunctionContext } from "cloud-function-engine" +import { addFunctionLog } from "../api/function-log" /** @@ -8,7 +9,7 @@ import { CloudFunction, FunctionContext } from "cloud-function-engine" * @param param 函数运行参数 * @returns */ -export async function invokeInFunction(name: string, param: FunctionContext) { +export async function invokeInFunction(name: string, param?: FunctionContext) { const data = await getFunctionByName(name) const func = new CloudFunction(data) @@ -18,15 +19,26 @@ export async function invokeInFunction(name: string, param: FunctionContext) { param = param ?? {} - if (param.requestId) { - param.requestId = this.param.requestId - } + param.requestId = param.requestId ?? 'invoke' - if (param.method) { - param.method = param.method ?? 'call' - } + param.method = param.method ?? 'call' const result = await func.invoke(param) - return result + await addFunctionLog({ + requestId: param.requestId, + method: param.method, + func_id: func.id, + func_name: name, + logs: result.logs, + time_usage: result.time_usage, + data: result.data, + error: result.error, + }) + + if (result.error) { + throw result.error + } + + return result.data } \ No newline at end of file diff --git a/packages/app-service/src/config.ts b/packages/app-service/src/config.ts index dea3dad676..3313fc44fe 100644 --- a/packages/app-service/src/config.ts +++ b/packages/app-service/src/config.ts @@ -99,4 +99,15 @@ export default class Config { static get isProd(): boolean { return process.env.NODE_ENV === 'production' } + + /** + * Expired time of function logs, in seconds + */ + static get FUNCTION_LOG_EXPIRED_TIME(): number { + return (process.env.FUNCTION_LOG_EXPIRED_TIME ?? 3600 * 24 * 30) as number + } + + static get APP_VERSION(): number { + return process.env.APP_VERSION as any as number + } } \ No newline at end of file diff --git a/packages/app-service/src/lib/database/index.ts b/packages/app-service/src/lib/database/index.ts index 4f4aac7d93..56ee757251 100644 --- a/packages/app-service/src/lib/database/index.ts +++ b/packages/app-service/src/lib/database/index.ts @@ -1,7 +1,7 @@ /* * @Author: Maslow * @Date: 2021-08-16 15:29:15 - * @LastEditTime: 2021-10-08 14:34:37 + * @LastEditTime: 2021-11-03 17:10:04 * @Description: */ @@ -10,6 +10,7 @@ import { MongoAccessor } from 'database-proxy' import Config from '../../config' import { createLogger, logger } from '../logger' import * as mongodb_uri from 'mongodb-uri' +import { ensureCollectionIndexes } from '../../api/indexes' /** @@ -44,6 +45,7 @@ export class DatabaseAgent { accessor.init() .then(async () => { logger.info('db connected') + await ensureCollectionIndexes() }) .catch(error => { logger.error(error) diff --git a/packages/app-service/src/router/function/debug.ts b/packages/app-service/src/router/function/debug.ts index 1df8b6b301..b6d1701ecc 100644 --- a/packages/app-service/src/router/function/debug.ts +++ b/packages/app-service/src/router/function/debug.ts @@ -1,7 +1,7 @@ /* * @Author: Maslow * @Date: 2021-07-30 10:30:29 - * @LastEditTime: 2021-11-01 18:55:44 + * @LastEditTime: 2021-11-03 19:41:03 * @Description: */ @@ -10,6 +10,7 @@ import { FunctionContext, CloudFunction } from 'cloud-function-engine' import { parseToken } from '../../lib/utils/token' import { logger } from '../../lib/logger' import { addFunctionLog } from '../../api/function-log' +import { ObjectId } from 'bson' /** * Handler of debugging cloud function @@ -51,12 +52,11 @@ export async function handleDebugFunction(req: Request, res: Response) { // log this execution to db await addFunctionLog({ requestId: requestId, - func_id: func.id, + method: req.method, + func_id: new ObjectId(func.id), func_name: func_name, logs: result.logs, time_usage: result.time_usage, - created_at: Date.now(), - updated_at: Date.now(), created_by: req['auth']?.uid, data: result.data, error: result.error, @@ -76,7 +76,11 @@ export async function handleDebugFunction(req: Request, res: Response) { logger.trace(requestId, `invoke ${func_name} invoke success: `, result) if (res.writableEnded === false) { - return res.send(result.data) + let data = result.data + if (typeof result.data === 'number') { + data = Number(result.data).toString() + } + return res.send(data) } } catch (error) { logger.error(requestId, 'failed to invoke error', error) diff --git a/packages/app-service/src/router/function/invoke.ts b/packages/app-service/src/router/function/invoke.ts index 04f61a09c0..6c612f7574 100644 --- a/packages/app-service/src/router/function/invoke.ts +++ b/packages/app-service/src/router/function/invoke.ts @@ -1,7 +1,7 @@ /* * @Author: Maslow * @Date: 2021-07-30 10:30:29 - * @LastEditTime: 2021-09-15 15:03:28 + * @LastEditTime: 2021-11-03 18:02:23 * @Description: */ @@ -56,12 +56,11 @@ export async function handleInvokeFunction(req: Request, res: Response) { if (Config.ENABLE_CLOUD_FUNCTION_LOG === 'always') { await addFunctionLog({ requestId: requestId, + method: req.method, func_id: func.id, func_name: func_name, logs: result.logs, time_usage: result.time_usage, - created_at: Date.now(), - updated_at: Date.now(), created_by: req['auth']?.uid, data: result.data, error: result.error, diff --git a/packages/cloud-function/package-lock.json b/packages/cloud-function/package-lock.json index 99f3064296..f01ab5cf1b 100644 --- a/packages/cloud-function/package-lock.json +++ b/packages/cloud-function/package-lock.json @@ -9,7 +9,7 @@ "version": "0.6.0-alpha.3", "license": "ISC", "dependencies": { - "moment": "^2.29.1" + "dayjs": "^1.10.7" }, "devDependencies": { "@types/express": "^4.17.11", @@ -93,13 +93,10 @@ "@types/node": "*" } }, - "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "engines": { - "node": "*" - } + "node_modules/dayjs": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", + "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" }, "node_modules/typescript": { "version": "4.3.5", @@ -192,10 +189,10 @@ "@types/node": "*" } }, - "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + "dayjs": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", + "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" }, "typescript": { "version": "4.3.5", diff --git a/packages/cloud-function/package.json b/packages/cloud-function/package.json index b37c4f79ef..73dc55a203 100644 --- a/packages/cloud-function/package.json +++ b/packages/cloud-function/package.json @@ -36,7 +36,7 @@ "url": "https://github.com/Maslow/less-framework/issues" }, "dependencies": { - "moment": "^2.29.1" + "dayjs": "^1.10.7" }, "devDependencies": { "@types/express": "^4.17.11", diff --git a/packages/cloud-function/src/console.ts b/packages/cloud-function/src/console.ts index 37b920b8de..9d539d4644 100644 --- a/packages/cloud-function/src/console.ts +++ b/packages/cloud-function/src/console.ts @@ -1,5 +1,5 @@ import * as util from 'util' -import * as moment from 'moment' +import * as dayjs from 'dayjs' export class FunctionConsole { private _logs: any[] = [] @@ -9,13 +9,13 @@ export class FunctionConsole { } log(...params: any[]) { - const date = moment().format("YYYY/MM/DD HH:mm:ss") + const date = dayjs().format("YYYY/MM/DD HH:mm:ss") const r = util.format("[%s] -", date, ...params) this._logs.push(r) } error(...params: any[]) { - const date = moment().format("YYYY/MM/DD HH:mm:ss") + const date = dayjs().format("YYYY/MM/DD HH:mm:ss") const r = util.format("[%s] -", date, ...params) this._logs.push(r) } diff --git a/packages/cloud-function/src/engine.ts b/packages/cloud-function/src/engine.ts index d4b7429c3a..3a8f7f7e80 100644 --- a/packages/cloud-function/src/engine.ts +++ b/packages/cloud-function/src/engine.ts @@ -39,8 +39,6 @@ export class FunctionEngine { */ async run(code: string, context: FunctionContext): Promise { const sandbox = this.buildSandbox(context) - - const wrapped = this.wrap(code) const fconsole = sandbox.console diff --git a/packages/cloud-function/src/trigger-scheduler.ts b/packages/cloud-function/src/trigger-scheduler.ts index 57d502acc9..9caa0968cd 100644 --- a/packages/cloud-function/src/trigger-scheduler.ts +++ b/packages/cloud-function/src/trigger-scheduler.ts @@ -46,10 +46,10 @@ export class TriggerScheduler { this._triggers.push(trigger) } else { // 若为定时器,则保留其 `最近一次执行时间` - if(trigger.isTimer) { + if (trigger.isTimer) { trigger.last_exec_time = this._triggers[index].last_exec_time ?? 0 } - + this._triggers[index] = trigger } @@ -86,7 +86,7 @@ export class TriggerScheduler { * @param func_id 函数ID * @returns */ - protected async getFunctionById(_func_id: string): Promise{ + protected async getFunctionById(_func_id: string): Promise { throw new Error('not implemented, you should drive TriggerScheduler class and override getFunctionById() method') } @@ -104,12 +104,11 @@ export class TriggerScheduler { result.logs.unshift(`invoked by trigger: ${trigger.name} (${trigger.id})`) await this.addFunctionLog({ requestId: `trigger_${trigger.id}`, + method: param.method, func_id: func.id, func_name: func.name, logs: result.logs, time_usage: result.time_usage, - created_at: Date.now(), - updated_at: Date.now(), created_by: `trigger_${trigger.id}`, trigger_id: trigger.id }) @@ -136,7 +135,7 @@ export class TriggerScheduler { /** * 开始调度定时触发器 */ - protected scheduleTimer() { + protected scheduleTimer() { this.cancelTimer() this._timer = setInterval(this.timerLoop.bind(this), 1000) } @@ -163,7 +162,7 @@ export class TriggerScheduler { * @param triggerId * @returns */ - protected removeTrigger(triggerId: string): boolean { + protected removeTrigger(triggerId: string): boolean { const index = this._triggers.findIndex(t => t.id === triggerId) if (index === -1) { return false diff --git a/packages/cloud-function/src/types.ts b/packages/cloud-function/src/types.ts index 7b1d9545ae..efc09eb449 100644 --- a/packages/cloud-function/src/types.ts +++ b/packages/cloud-function/src/types.ts @@ -40,7 +40,7 @@ export interface FunctionContext { export interface FunctionResult { data?: any, logs: any[], - error?: any, + error?: Error, time_usage: number } diff --git a/packages/system-client/src/utils/index.js b/packages/system-client/src/utils/index.js index 3225d3c4c2..194592ff36 100644 --- a/packages/system-client/src/utils/index.js +++ b/packages/system-client/src/utils/index.js @@ -24,7 +24,7 @@ export function parseTime(time, cFormat) { } else { // support safari // https://stackoverflow.com/questions/4310953/invalid-date-in-safari - time = time.replace(new RegExp(/-/gm), '/') + // time = time.replace(new RegExp(/-/gm), '/') } } diff --git a/packages/system-client/src/views/cloudfunction/components/FunctionLogDetail.vue b/packages/system-client/src/views/cloudfunction/components/FunctionLogDetail.vue index 44a2259d69..67af470913 100644 --- a/packages/system-client/src/views/cloudfunction/components/FunctionLogDetail.vue +++ b/packages/system-client/src/views/cloudfunction/components/FunctionLogDetail.vue @@ -14,6 +14,11 @@
- {{ log }}
+ +
返回结果
+
+
{{ returnValue }}
+
@@ -34,11 +39,15 @@ export default { computed: { // 云函数的日志 logs() { - return this.data.logs + return this.data?.logs }, // 云函数执行用时 invokeTime() { - return this.data.time_usage + return this.data?.time_usage + }, + // 云函数调用结果 + returnValue() { + return this.data?.data } }, async created() { diff --git a/packages/system-client/src/views/cloudfunction/debug.vue b/packages/system-client/src/views/cloudfunction/debug.vue index 9c430ed0b3..7578925e4b 100644 --- a/packages/system-client/src/views/cloudfunction/debug.vue +++ b/packages/system-client/src/views/cloudfunction/debug.vue @@ -48,12 +48,9 @@ 刷新
- {{ log.created_at | parseTime('{y}-{m}-{d} {h}:{i}:{s}') }} - -
@@ -89,7 +86,7 @@ :dark="false" /> -
+
执行日志