@budibase/server 2.6.19-alpha.30 → 2.6.19-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "2.6.19-alpha.30",
4
+ "version": "2.6.19-alpha.31",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -46,12 +46,12 @@
46
46
  "license": "GPL-3.0",
47
47
  "dependencies": {
48
48
  "@apidevtools/swagger-parser": "10.0.3",
49
- "@budibase/backend-core": "2.6.19-alpha.30",
50
- "@budibase/client": "2.6.19-alpha.30",
51
- "@budibase/pro": "2.6.19-alpha.30",
52
- "@budibase/shared-core": "2.6.19-alpha.30",
53
- "@budibase/string-templates": "2.6.19-alpha.30",
54
- "@budibase/types": "2.6.19-alpha.30",
49
+ "@budibase/backend-core": "2.6.19-alpha.31",
50
+ "@budibase/client": "2.6.19-alpha.31",
51
+ "@budibase/pro": "2.6.19-alpha.31",
52
+ "@budibase/shared-core": "2.6.19-alpha.31",
53
+ "@budibase/string-templates": "2.6.19-alpha.31",
54
+ "@budibase/types": "2.6.19-alpha.31",
55
55
  "@bull-board/api": "3.7.0",
56
56
  "@bull-board/koa": "3.9.4",
57
57
  "@elastic/elasticsearch": "7.10.0",
@@ -100,6 +100,7 @@
100
100
  "mssql": "6.2.3",
101
101
  "mysql2": "2.3.3",
102
102
  "node-fetch": "2.6.7",
103
+ "object-sizeof": "2.6.1",
103
104
  "open": "8.4.0",
104
105
  "openai": "^3.2.1",
105
106
  "pg": "8.10.0",
@@ -195,5 +196,5 @@
195
196
  }
196
197
  }
197
198
  },
198
- "gitHead": "c62ae2d9ea7f29de54c4cb6ef9a8f22e82eb8460"
199
+ "gitHead": "46abe5917ecc3ed921f10dfd9aff09f1970f80c3"
199
200
  }
@@ -2,6 +2,23 @@ import env from "../../environment"
2
2
  import { AutomationResults, Automation, App } from "@budibase/types"
3
3
  import { automations } from "@budibase/pro"
4
4
  import { db as dbUtils } from "@budibase/backend-core"
5
+ import sizeof from "object-sizeof"
6
+
7
+ const MAX_LOG_SIZE_MB = 5
8
+ const MB_IN_BYTES = 1024 * 1024
9
+
10
+ function sanitiseResults(results: AutomationResults) {
11
+ const message = `[removed] - max results size of ${MAX_LOG_SIZE_MB}MB exceeded`
12
+ for (let step of results.steps) {
13
+ step.inputs = {
14
+ message,
15
+ }
16
+ step.outputs = {
17
+ message,
18
+ success: step.outputs.success,
19
+ }
20
+ }
21
+ }
5
22
 
6
23
  export async function storeLog(
7
24
  automation: Automation,
@@ -11,6 +28,10 @@ export async function storeLog(
11
28
  if (env.DISABLE_AUTOMATION_LOGS) {
12
29
  return
13
30
  }
31
+ const bytes = sizeof(results)
32
+ if (bytes / MB_IN_BYTES > MAX_LOG_SIZE_MB) {
33
+ sanitiseResults(results)
34
+ }
14
35
  await automations.logs.storeLog(automation, results)
15
36
  }
16
37
 
@@ -80,6 +80,7 @@ const environment = {
80
80
  ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
81
81
  SELF_HOSTED: process.env.SELF_HOSTED,
82
82
  HTTP_MB_LIMIT: process.env.HTTP_MB_LIMIT,
83
+ FORKED_PROCESS_NAME: process.env.FORKED_PROCESS_NAME || "main",
83
84
  // old
84
85
  CLIENT_ID: process.env.CLIENT_ID,
85
86
  _set(key: string, value: any) {
@@ -19,6 +19,7 @@ import {
19
19
  AutomationStatus,
20
20
  AutomationMetadata,
21
21
  AutomationJob,
22
+ AutomationData,
22
23
  } from "@budibase/types"
23
24
  import {
24
25
  LoopStep,
@@ -37,8 +38,8 @@ const LOOP_STEP_ID = actions.BUILTIN_ACTION_DEFINITIONS.LOOP.stepId
37
38
  const CRON_STEP_ID = triggerDefs.CRON.stepId
38
39
  const STOPPED_STATUS = { success: true, status: AutomationStatus.STOPPED }
39
40
 
40
- function getLoopIterations(loopStep: LoopStep, input: LoopInput) {
41
- const binding = automationUtils.typecastForLooping(loopStep, input)
41
+ function getLoopIterations(loopStep: LoopStep) {
42
+ let binding = loopStep.inputs.binding
42
43
  if (!binding) {
43
44
  return 0
44
45
  }
@@ -68,7 +69,6 @@ class Orchestrator {
68
69
  constructor(job: AutomationJob) {
69
70
  let automation = job.data.automation
70
71
  let triggerOutput = job.data.event
71
- let timeout = job.data.event.timeout
72
72
  const metadata = triggerOutput.metadata
73
73
  this._chainCount = metadata ? metadata.automationChainCount! : 0
74
74
  this._appId = triggerOutput.appId as string
@@ -252,7 +252,7 @@ class Orchestrator {
252
252
  return
253
253
  }
254
254
  }
255
-
255
+ const start = performance.now()
256
256
  for (let step of automation.definition.steps) {
257
257
  if (timeoutFlag) {
258
258
  break
@@ -277,22 +277,17 @@ class Orchestrator {
277
277
 
278
278
  if (loopStep) {
279
279
  input = await processObject(loopStep.inputs, this._context)
280
- iterations = getLoopIterations(loopStep as LoopStep, input)
280
+ iterations = getLoopIterations(loopStep as LoopStep)
281
281
  }
282
282
  for (let index = 0; index < iterations; index++) {
283
283
  let originalStepInput = cloneDeep(step.inputs)
284
284
  // Handle if the user has set a max iteration count or if it reaches the max limit set by us
285
285
  if (loopStep && input.binding) {
286
- let newInput: any = await processObject(
287
- loopStep.inputs,
288
- cloneDeep(this._context)
289
- )
290
-
291
286
  let tempOutput = { items: loopSteps, iterations: iterationCount }
292
287
  try {
293
- newInput.binding = automationUtils.typecastForLooping(
288
+ loopStep.inputs.binding = automationUtils.typecastForLooping(
294
289
  loopStep as LoopStep,
295
- newInput
290
+ loopStep.inputs as LoopInput
296
291
  )
297
292
  } catch (err) {
298
293
  this.updateContextAndOutput(loopStepNumber, step, tempOutput, {
@@ -303,13 +298,12 @@ class Orchestrator {
303
298
  loopStep = undefined
304
299
  break
305
300
  }
306
-
307
301
  let item = []
308
302
  if (
309
303
  typeof loopStep.inputs.binding === "string" &&
310
304
  loopStep.inputs.option === "String"
311
305
  ) {
312
- item = automationUtils.stringSplit(newInput.binding)
306
+ item = automationUtils.stringSplit(loopStep.inputs.binding)
313
307
  } else if (Array.isArray(loopStep.inputs.binding)) {
314
308
  item = loopStep.inputs.binding
315
309
  }
@@ -351,6 +345,7 @@ class Orchestrator {
351
345
  }
352
346
  }
353
347
  }
348
+
354
349
  if (
355
350
  index === env.AUTOMATION_MAX_ITERATIONS ||
356
351
  index === parseInt(loopStep.inputs.iterations)
@@ -479,8 +474,22 @@ class Orchestrator {
479
474
  }
480
475
  }
481
476
 
477
+ const end = performance.now()
478
+ const executionTime = end - start
479
+
480
+ console.log(`Execution time: ${executionTime} milliseconds`)
481
+
482
482
  // store the logs for the automation run
483
- await storeLog(this._automation, this.executionOutput)
483
+ try {
484
+ await storeLog(this._automation, this.executionOutput)
485
+ } catch (e: any) {
486
+ if (e.status === 413 && e.request?.data) {
487
+ // if content is too large we shouldn't log it
488
+ delete e.request.data
489
+ e.request.data = { message: "removed due to large size" }
490
+ }
491
+ logging.logAlert("Error writing automation log", e)
492
+ }
484
493
  if (isProdAppID(this._appId) && isRecurring(automation) && metadata) {
485
494
  await this.updateMetadata(metadata)
486
495
  }
@@ -488,23 +497,31 @@ class Orchestrator {
488
497
  }
489
498
  }
490
499
 
491
- export function execute(job: Job, callback: WorkerCallback) {
500
+ export function execute(job: Job<AutomationData>, callback: WorkerCallback) {
492
501
  const appId = job.data.event.appId
502
+ const automationId = job.data.automation._id
493
503
  if (!appId) {
494
504
  throw new Error("Unable to execute, event doesn't contain app ID.")
495
505
  }
496
- return context.doInAppContext(appId, async () => {
497
- const envVars = await sdkUtils.getEnvironmentVariables()
498
- // put into automation thread for whole context
499
- await context.doInEnvironmentContext(envVars, async () => {
500
- const automationOrchestrator = new Orchestrator(job)
501
- try {
502
- const response = await automationOrchestrator.execute()
503
- callback(null, response)
504
- } catch (err) {
505
- callback(err)
506
- }
507
- })
506
+ if (!automationId) {
507
+ throw new Error("Unable to execute, event doesn't contain automation ID.")
508
+ }
509
+ return context.doInAutomationContext({
510
+ appId,
511
+ automationId,
512
+ task: async () => {
513
+ const envVars = await sdkUtils.getEnvironmentVariables()
514
+ // put into automation thread for whole context
515
+ await context.doInEnvironmentContext(envVars, async () => {
516
+ const automationOrchestrator = new Orchestrator(job)
517
+ try {
518
+ const response = await automationOrchestrator.execute()
519
+ callback(null, response)
520
+ } catch (err) {
521
+ callback(err)
522
+ }
523
+ })
524
+ },
508
525
  })
509
526
  }
510
527
 
@@ -38,6 +38,9 @@ export class Thread {
38
38
  this.count = opts.count ? opts.count : 1
39
39
  this.disableThreading = this.shouldDisableThreading()
40
40
  if (!this.disableThreading) {
41
+ console.debug(
42
+ `[${env.FORKED_PROCESS_NAME}] initialising worker farm type=${type}`
43
+ )
41
44
  const workerOpts: any = {
42
45
  autoStart: true,
43
46
  maxConcurrentWorkers: this.count,
@@ -45,6 +48,7 @@ export class Thread {
45
48
  env: {
46
49
  ...process.env,
47
50
  FORKED_PROCESS: "1",
51
+ FORKED_PROCESS_NAME: type,
48
52
  },
49
53
  },
50
54
  }
@@ -54,6 +58,10 @@ export class Thread {
54
58
  }
55
59
  this.workers = workerFarm(workerOpts, typeToFile(type), ["execute"])
56
60
  Thread.workerRefs.push(this.workers)
61
+ } else {
62
+ console.debug(
63
+ `[${env.FORKED_PROCESS_NAME}] skipping worker farm type=${type}`
64
+ )
57
65
  }
58
66
  }
59
67
 
@@ -72,9 +80,7 @@ export class Thread {
72
80
  function fire(worker: any) {
73
81
  worker.execute(job, (err: any, response: any) => {
74
82
  if (err && err.type === "TimeoutError") {
75
- reject(
76
- new Error(`Query response time exceeded ${timeout}ms timeout.`)
77
- )
83
+ reject(new Error(`Thread timeout exceeded ${timeout}ms timeout.`))
78
84
  } else if (err) {
79
85
  reject(err)
80
86
  } else {
@@ -26,8 +26,10 @@ function makeVariableKey(queryId: string, variable: string) {
26
26
  export function threadSetup() {
27
27
  // don't run this if not threading
28
28
  if (env.isTest() || env.DISABLE_THREADING || !env.isInThread()) {
29
+ console.debug(`[${env.FORKED_PROCESS_NAME}] thread setup skipped`)
29
30
  return
30
31
  }
32
+ console.debug(`[${env.FORKED_PROCESS_NAME}] thread setup running`)
31
33
  db.init()
32
34
  }
33
35