first commit
This commit is contained in:
55
services/web/scripts/lib/README.md
Normal file
55
services/web/scripts/lib/README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Script Runner
|
||||
|
||||
## Overview
|
||||
|
||||
The Script Runner wraps your script's main logic to automatically handle logging, status tracking (success/error), and progress updates. Script execution status can be viewed from "Script Logs" portal page.
|
||||
|
||||
## Features
|
||||
|
||||
- Automatically logs the start and end of your script.
|
||||
- Records the final status ('success' or 'error').
|
||||
- Provides a simple function (`trackProgress`) to your script for logging custom progress steps.
|
||||
- Captures script parameters and basic environment details.
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Import `scriptRunner`**.
|
||||
2. **Define your script's main logic** as an `async` function that accepts `trackProgress` as its argument (can ignore `trackProgress` if you don't need to track progress).
|
||||
3. **Call `scriptRunner`**, passing your function and any variables it needs.
|
||||
4. **Check script execution status** by visiting the "Script Logs" portal page using the URL printed in the console output.
|
||||
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
// Import the script runner utility (adjust the path as needed)
|
||||
import { scriptRunner } from './lib/ScriptRunner.mjs'
|
||||
|
||||
const subJobs = 30
|
||||
|
||||
/**
|
||||
* Your script's main work goes here.
|
||||
* It must be an async function and accept `trackProgress`.
|
||||
* @param {(message: string) => void} trackProgress - Call this to log progress.
|
||||
*/
|
||||
async function main(trackProgress) {
|
||||
for (let i = 0; i < subJobs; i++) {
|
||||
await new Promise(resolve => setTimeout(() => resolve(), 1000))
|
||||
await trackProgress(`Job in progress ${i + 1}/${subJobs}`)
|
||||
}
|
||||
await trackProgress('Job finished')
|
||||
}
|
||||
|
||||
// Define any variables your script needs (optional)
|
||||
const scriptVariables = {
|
||||
subJobs,
|
||||
}
|
||||
|
||||
// --- Execute the script using the runner with async/await ---
|
||||
try {
|
||||
await scriptRunner(main, scriptVariables)
|
||||
process.exit()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
}
|
||||
```
|
75
services/web/scripts/lib/ScriptRunner.mjs
Normal file
75
services/web/scripts/lib/ScriptRunner.mjs
Normal file
@@ -0,0 +1,75 @@
|
||||
import { ScriptLog } from '../../app/src/models/ScriptLog.mjs'
|
||||
import Settings from '@overleaf/settings'
|
||||
|
||||
async function beforeScriptExecution(canonicalName, vars, scriptPath) {
|
||||
let log = new ScriptLog({
|
||||
canonicalName,
|
||||
filePathAtVersion: scriptPath,
|
||||
podName: process.env.OL_POD_NAME,
|
||||
username: process.env.OL_USERNAME,
|
||||
imageVersion: process.env.OL_IMAGE_VERSION,
|
||||
vars,
|
||||
})
|
||||
log = await log.save()
|
||||
console.log(
|
||||
'\n==================================' +
|
||||
'\n✨ Your script is running!' +
|
||||
'\n📊 Track progress at:' +
|
||||
`\n${Settings.adminUrl}/admin/script-log/${log._id}` +
|
||||
'\n==================================\n'
|
||||
)
|
||||
return log._id
|
||||
}
|
||||
|
||||
async function afterScriptExecution(logId, status) {
|
||||
await ScriptLog.findByIdAndUpdate(logId, { status, endTime: new Date() })
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(trackProgress: (progress: string) => Promise<void>) => Promise<any>} main - Main function for the script
|
||||
* @param {Object} vars - Variables to be used in the script
|
||||
* @param {string} canonicalName - The canonical name of the script, default to filename
|
||||
* @param {string} scriptPath - The file path of the script, default to process.argv[1]
|
||||
* @returns {Promise<void>}
|
||||
* @async
|
||||
*/
|
||||
export async function scriptRunner(
|
||||
main,
|
||||
vars = {},
|
||||
canonicalName = process.argv[1].split('/').pop().split('.')[0],
|
||||
scriptPath = process.argv[1]
|
||||
) {
|
||||
const isSaaS = Boolean(Settings.overleaf)
|
||||
if (!isSaaS) {
|
||||
await main(async message => {
|
||||
console.warn(message)
|
||||
})
|
||||
return
|
||||
}
|
||||
const logId = await beforeScriptExecution(canonicalName, vars, scriptPath)
|
||||
|
||||
async function trackProgress(message) {
|
||||
try {
|
||||
console.warn(message)
|
||||
await ScriptLog.findByIdAndUpdate(logId, {
|
||||
$push: {
|
||||
progressLogs: {
|
||||
timestamp: new Date(),
|
||||
message,
|
||||
},
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error tracking progress:', error)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await main(trackProgress)
|
||||
} catch (error) {
|
||||
await afterScriptExecution(logId, 'error')
|
||||
throw error
|
||||
}
|
||||
|
||||
await afterScriptExecution(logId, 'success')
|
||||
}
|
Reference in New Issue
Block a user