1
0
Fork 0
mirror of synced 2024-10-02 10:08:09 +13:00

Merge branch 'master' of github.com:Budibase/budibase into cheeks-snippets-poc

This commit is contained in:
Andrew Kingston 2024-03-13 10:21:07 +00:00
commit e45beff059
8 changed files with 51 additions and 44 deletions

View file

@ -1,5 +1,5 @@
{
"version": "2.21.8",
"version": "2.21.9",
"npmClient": "yarn",
"packages": [
"packages/*",

View file

@ -1,5 +1,4 @@
import { IdentityContext, Snippet, VM } from "@budibase/types"
import { ExecutionTimeTracker } from "../timers"
// keep this out of Budibase types, don't want to expose context info
export type ContextMap = {
@ -10,7 +9,7 @@ export type ContextMap = {
isScim?: boolean
automationId?: string
isMigrating?: boolean
jsExecutionTracker?: ExecutionTimeTracker
vm?: VM
cleanup?: (() => void | Promise<void>)[]
snippets?: Snippet[]
}

View file

@ -20,41 +20,3 @@ export function cleanup() {
}
intervals = []
}
export class ExecutionTimeoutError extends Error {
public readonly name = "ExecutionTimeoutError"
}
export class ExecutionTimeTracker {
static withLimit(limitMs: number) {
return new ExecutionTimeTracker(limitMs)
}
constructor(readonly limitMs: number) {}
private totalTimeMs = 0
track<T>(f: () => T): T {
this.checkLimit()
const start = process.hrtime.bigint()
try {
return f()
} finally {
const end = process.hrtime.bigint()
this.totalTimeMs += Number(end - start) / 1e6
this.checkLimit()
}
}
get elapsedMS() {
return this.totalTimeMs
}
checkLimit() {
if (this.totalTimeMs > this.limitMs) {
throw new ExecutionTimeoutError(
`Execution time limit of ${this.limitMs}ms exceeded: ${this.totalTimeMs}ms`
)
}
}
}

View file

@ -1,6 +1,7 @@
import Router from "@koa/router"
import { auth, middleware, env as envCore } from "@budibase/backend-core"
import currentApp from "../middleware/currentapp"
import cleanup from "../middleware/cleanup"
import zlib from "zlib"
import { mainRoutes, staticRoutes, publicRoutes } from "./routes"
import { middleware as pro } from "@budibase/pro"
@ -62,6 +63,8 @@ if (apiEnabled()) {
.use(auth.auditLog)
// @ts-ignore
.use(migrations)
// @ts-ignore
.use(cleanup)
// authenticated routes
for (let route of mainRoutes) {

View file

@ -8,6 +8,7 @@ import {
import { context, logging } from "@budibase/backend-core"
import tracer from "dd-trace"
import { IsolatedVM } from "./vm"
import type { VM } from "@budibase/types"
export function init() {
setJSRunner((js: string, ctx: Record<string, any>) => {
@ -26,12 +27,15 @@ export function init() {
.withSnippets(bbCtx?.snippets)
// Persist isolate in context so we can reuse it
if (bbCtx) {
if (bbCtx && !bbCtx.vm) {
bbCtx.vm = vm
bbCtx.cleanup = bbCtx.cleanup || []
bbCtx.cleanup.push(() => vm.close())
}
// Strip helpers (an array) and snippets (a proxy isntance) as these
// will not survive the isolated-vm barrier
// Because we can't pass functions into an Isolate, we remove them from
// the passed context and rely on the withHelpers() method to add them
// back in.
const { helpers, snippets, ...rest } = ctx
return vm.withContext(rest, () => vm.execute(js))
} catch (error: any) {

View file

@ -209,6 +209,11 @@ export class IsolatedVM implements VM {
return result[this.runResultKey]
}
close(): void {
this.vm.release()
this.isolate.dispose()
}
private registerCallbacks(functions: Record<string, any>) {
const libId = crypto.randomUUID().replace(/-/g, "")

View file

@ -0,0 +1,33 @@
import { Ctx } from "@budibase/types"
import { context } from "@budibase/backend-core"
import { tracer } from "dd-trace"
export default async (ctx: Ctx, next: any) => {
const resp = await next()
const current = context.getCurrentContext()
if (!current || !current.cleanup) {
return resp
}
let errors = []
for (let fn of current.cleanup) {
try {
await tracer.trace("cleanup", async span => {
await fn()
})
} catch (e) {
// We catch errors here to ensure we at least attempt to run all cleanup
// functions. We'll throw the first error we encounter after all cleanup
// functions have been run.
errors.push(e)
}
}
delete current.cleanup
if (errors.length > 0) {
throw errors[0]
}
return resp
}

View file

@ -1,4 +1,5 @@
export interface VM {
execute(code: string): any
withContext<T>(context: Record<string, any>, executeWithContext: () => T): T
close(): void
}