diff --git a/server/src/workflow-management/scheduler/index.ts b/server/src/workflow-management/scheduler/index.ts index f5b1c7d6..2272c4c4 100644 --- a/server/src/workflow-management/scheduler/index.ts +++ b/server/src/workflow-management/scheduler/index.ts @@ -1,7 +1,7 @@ import { Queue, Worker } from 'bullmq'; import IORedis from 'ioredis'; import { deleteFile, readFile, readFiles, saveFile } from "../storage"; -import { createRemoteBrowserForRun, destroyRemoteBrowser } from '../../browser-management/controller'; +import { createRemoteBrowserForRun, destroyRemoteBrowser, getActiveBrowserId } from '../../browser-management/controller'; import logger from '../../logger'; import { browserPool } from "../../server"; import fs from "fs"; @@ -44,18 +44,21 @@ worker.on('failed', (job: any, err) => { }); async function runWorkflow(fileName: string, runId: string) { + if (!runId) { + runId = uuid(); + } + + // Phase 1: Scheduling try { const browserId = createRemoteBrowserForRun({ browser: chromium, launchOptions: { headless: true } }); + logger.log(`debug`,`Created browser with ID: ${browserId}`); - if (!runId) { - runId = uuid(); - } const run_meta = { - status: 'RUNNING', + status: 'SCHEDULED', name: fileName, startedAt: new Date().toLocaleString(), finishedAt: '', @@ -73,18 +76,102 @@ async function runWorkflow(fileName: string, runId: string) { JSON.stringify(run_meta, null, 2) ); - logger.log('debug', `Scheduled run with name: ${fileName}.json`); + logger.log('debug', `Scheduled run with name: ${fileName}_${runId}.json`); + + logger.log('debug', `Active in run : ${getActiveBrowserId()}`); + + // Phase 2: Running + return await executeRun(fileName, runId); - return { - browserId: browserId, - runId: runId, - }; } catch (e) { const { message } = e as Error; - logger.log('info', `Error while scheduling a run with name: ${fileName}.json`); - console.log(message) - return false; + logger.log('info', `Error while scheduling a run with name: ${fileName}_${runId}.json`); + console.log(message); + return { + success: false, + error: message, + }; } } +async function executeRun(fileName: string, runId: string) { + try { + // Read the recording from storage + const recording = await readFile(`./../storage/recordings/${fileName}.waw.json`); + const parsedRecording = JSON.parse(recording); + + // Read the run from storage + const run = await readFile(`./../storage/runs/${fileName}_${runId}.json`); + const parsedRun = JSON.parse(run); + + // Update status to RUNNING + parsedRun.status = 'RUNNING'; + await saveFile( + `../storage/runs/${fileName}_${runId}.json`, + JSON.stringify(parsedRun, null, 2) + ); + + // Interpret the run in active browser + + logger.log('debug', `Active in exec : ${getActiveBrowserId()}`); + const browser = browserPool.getRemoteBrowser(parsedRun.browserId); + if (!browser) { + throw new Error('Could not access browser'); + } + + const currentPage = await browser.getCurrentPage(); + if (!currentPage) { + throw new Error('Could not create a new page'); + } + + const interpretationInfo = await browser.interpreter.InterpretRecording( + parsedRecording.recording, currentPage, parsedRun.interpreterSettings); + + const duration = Math.round((new Date().getTime() - new Date(parsedRun.startedAt).getTime()) / 1000); + const durString = duration < 60 ? `${duration} s` : `${Math.floor(duration / 60)} m ${duration % 60} s`; + + await destroyRemoteBrowser(parsedRun.browserId); + + const updated_run_meta = { + ...parsedRun, + status: interpretationInfo.result, + finishedAt: new Date().toLocaleString(), + duration: durString, + browserId: null, + log: interpretationInfo.log.join('\n'), + serializableOutput: interpretationInfo.serializableOutput, + binaryOutput: interpretationInfo.binaryOutput, + }; + + await saveFile( + `../storage/runs/${fileName}_${runId}.json`, + JSON.stringify(updated_run_meta, null, 2) + ); + + return { + browserId: parsedRun.browserId, + runId: runId, + success: true, + }; + } catch (error: any) { + logger.log('info', `Error while running a recording with name: ${fileName}_${runId}.json`); + console.log(error.message); + + // Update run status to ERROR + const errorRun = await readFile(`./../storage/runs/${fileName}_${runId}.json`); + const parsedErrorRun = JSON.parse(errorRun); + parsedErrorRun.status = 'ERROR'; + parsedErrorRun.log += `\nError: ${error.message}`; + await saveFile( + `../storage/runs/${fileName}_${runId}.json`, + JSON.stringify(parsedErrorRun, null, 2) + ); + + return { + runId: runId, + success: false, + error: error.message, + }; + } +} export { workflowQueue, runWorkflow }; \ No newline at end of file