oJob YAML Reference Guide
oJob is OpenAF’s job orchestration framework that allows you to define, schedule, and execute jobs using YAML configuration files. This comprehensive guide covers all aspects of creating and using oJob YAML files.
Table of Contents
- Basic Structure
- Help Section
- Initialization
- oJob Configuration
- Todo List
- Including Other oJobs
- Job Definitions
- Code Separation
- Built-in Jobs
- Advanced Features
- Examples
Basic Structure
An oJob YAML file consists of several main sections:
# Optional: Help information
help:
text : "Description of what this oJob does"
expects:
- name: arg1
desc: "Description of argument 1"
# Optional: Initialization values
init:
someValue: "default value"
# Optional: oJob configuration
ojob:
daemon : false
logToConsole: true
# Optional: Include other oJob files
include:
- another-ojob.yaml
# Required: Job definitions
jobs:
- name: "My First Job"
exec: |
print("Hello World!")
# Required: Execution order
todo:
- "My First Job"
Help Section
The help section provides documentation for humans about what the oJob does and which arguments it expects.
help:
text : "Detailed description of the oJob functionality"
expects:
- name : inputFile
desc : "Path to the input file to process"
mandatory: true
example : "/path/to/file.txt"
- name : outputDir
desc : "Directory where results will be saved"
mandatory: false
example : "/tmp/output"
- name : verbose
desc : "Enable verbose logging"
options : ["true", "false"]
- name : mode
desc : "Processing mode"
moptions : ["fast", "thorough", "debug"]
- name : password
desc : "Authentication password"
secret : true
Help Properties
text: Main description of the oJobexpects: Array of expected argumentsname: Argument namedesc: Description of the argumentmandatory: Whether the argument is requiredexample: Example valueoptions: Array of valid values (single choice)moptions: Array of valid values (multiple choice)secret: Whether the argument should be hidden when prompted
Initialization
The init section provides default values that are available to all jobs as args.init.
init:
database:
host: "localhost"
port: 5432
apiEndpoint: "https://api.example.com"
retryCount: 3
timeout: 30000
oJob Configuration
The ojob section controls how the oJob executes and behaves.
Execution Control
ojob:
# Thread management
numThreads: 4 # Force specific number of threads
poolThreadFactor: 2 # Multiply cores by this factor
# Execution behavior
async: false # Execute jobs async instead of sequential
sequential: true # Force sequential execution
shareArgs: false # Share argument changes between jobs
daemon: false # Keep running as daemon
timeInterval: 50 # Daemon check interval in ms
# Dependencies
depsWait: false # Wait for dependencies even if others fail
depsTimeout: 300000 # Max time to wait for dependencies (ms)
depsOnFail: | # Code to execute when dependency fails
logErr("Dependency failed: " + job.name)
# Templates and arguments
templateArgs: true # Process {{}} handlebars in args
argsFromEnvs: true # Load environment variables as args
initTemplateEscape: false # Escape {{ in init values
# Timing
cronInLocalTime: false # Use local time for cron expressions
Logging Configuration
ojob:
# Console logging
logToConsole: true # Output job messages to stderr
logOJob: false # Use OpenAF logging for jobs
logJobs: true # Log job execution
logArgs: false # Log arguments before each job
logLimit: 3 # Number of executions to keep in log
logHistory: 10 # Factor of job logs to keep
ignoreNoLog: false # Ignore job-level nolog settings
# Console appearance
conAnsi: true # Enable ANSI terminal detection
conWidth: 128 # Force console width
# File logging
logToFile:
logFolder: "/var/log"
HKhowLongAgoInMinutes: 2880
# Structured logging
log:
format: json # Use JSON format
level: INFO
External Dependencies
ojob:
# Include built-in oJob definitions
includeOJob: true
# OpenAF Packages
opacks:
- openaf: ">=20230601" # Minimum version
- S3: ">=20230401"
- oJob-common # Latest version
# OpenWrap libraries
owraps:
- Server
- Java
# JavaScript libraries
loads:
- anotherJS.js
loadLibs:
- utils.js
Process Control
ojob:
# Unique execution
unique:
pidFile: "myjob.pid" # PID file for uniqueness
killPrevious: false # Kill previous instance
# Error handling
catch: | # Global error handler
logErr("Global error: " + exception)
# Stall detection
checkStall:
everySeconds: 60 # Check interval
killAfterSeconds: 120 # Kill after this time
checkFunc: | # Custom stall check function
return false // Add your logic here
Channel Management
ojob:
channels:
recordLog : false # Record OpenAF logs
recordLogHistory: -1 # Number of log entries to keep (-1 unlimited)
# Create channels
create:
- name: myChannel
type: mvs
options:
file: data.db
# Expose channels via HTTP
expose: true
port: 8080
host: "0.0.0.0"
# Authentication
auth:
- login: user1
pass: pass1
permissions: "rw"
# Peer connections
peers:
- "https://peer.example.com:8080/chs/myChannel"
# Clustering
clusters:
- name: mainCluster
checkPeriod: 2500
host: "localhost"
port: 8080
Metrics and Monitoring
ojob:
metrics:
# Passive metrics (expose endpoint)
passive: true
port: 8080
uri: "/metrics"
openMetrics: true
openMetricsPrefix: "ojob"
# Active metrics (push to external systems)
active:
openmetrics:
url: "http://pushgateway:9091/metrics/job/test"
prefix: "myapp"
metrics: ["custom-metric", "mem"]
nattrmon:
url: "http://user:pass@nattrmon:7777/remote"
attrPrefix: "oJob/"
metrics: ["custom-metric", "mem"]
periodInMs: 5000
# Collect metrics to channel
collect:
ch: metricsChannel
period: 5000
some: ["mem", "cpu"]
# Custom metrics
add:
custom-metric: |
return { value: Math.random() * 100 }
Language Support
ojob:
langs:
- lang: mylang
shell: "mylang -"
pre: "var args = JSON.parse('{{args}}');\n"
pos: "\nconsole.log(JSON.stringify(args));\n"
returnRE: "\\s*#\\s+return (.+)[\\s\\n]*$"
returnFn: |
return "console.log(JSON.stringify({" + _args + "}));"
Security and Integrity
ojob:
# File integrity checking
integrity:
list:
- "external-ojob.yaml": "sha256:abc123..."
- "https://remote.com/ojob": "md5:def456..."
strict: false # Reject if integrity fails
warn: true # Log warnings for integrity failures
# Debugging
debug: true # Enable debug mode for jobs
Todo List
The todo section defines what jobs to execute and in what order.
Simple Todo
todo:
- "Job 1" # Execute by name
- "Job 2"
- name: "Job 3" # Execute with custom args
args:
customParam: "value"
Conditional Execution
todo:
- name: "Conditional Job"
when: "production" # Only run when state is "production"
args:
env: "prod"
See below Job State Management for more on state management.
Multiple Arguments
todo:
- name: "Parallel Execution Job"
args:
- input: "file1.txt" # First execution
output: "result1.txt"
- input: "file2.txt" # Second execution (parallel)
output: "result2.txt"
Default Arguments in Todo
Todo entries also support default argument values using the "${key:-defaultValue}" syntax, allowing you to provide fallback values for arguments that may not be defined:
todo:
- name: "Job with Default Args"
args:
# Use "localhost" if "serverHost" is not defined
host: "${serverHost:-localhost}"
# Use 3306 if "dbPort" is not defined
port: "${dbPort:-3306}"
# Use existing value if "mode" is provided, otherwise use "default"
mode: "${mode:-default}"
# Works with nested paths - use "INFO" if config.log.level is not defined
logLevel: "${config.log.level:-INFO}"
Key features in todo entries:
- Runtime resolution: Default values are resolved when the todo entry is processed
- Inheritance: These processed arguments are passed to the target job
- Template integration: Works seamlessly with oJob’s template processing
- Nested support: Supports dot notation for nested object properties
- Type preservation: Values are processed as strings but maintain their intended types
Usage examples:
# Todo entry with various default patterns
todo:
- name: "Database Migration Job"
args:
# Database connection defaults
dbHost: "${DB_HOST:-localhost}"
dbPort: "${DB_PORT:-5432}"
dbName: "${DB_NAME:-myapp}"
# Processing options with defaults
batchSize: "${BATCH_SIZE:-1000}"
timeout: "${TIMEOUT:-30000}"
# Feature flags with defaults
dryRun: "${DRY_RUN:-false}"
verbose: "${VERBOSE:-true}"
# Nested configuration defaults
config:
retryCount: "${config.retries:-3}"
backoffMs: "${config.backoff:-5000}"
Including Other oJobs
Include Complete oJobs
include:
- "common-jobs.yaml" # Local file
- "MyOPack::jobs.yaml" # From an oPack
- "ojob.io/common/utils" # Remote oJob
Include Only Jobs (Not Todo)
jobsInclude:
- "job-definitions.yaml"
- "ojob.io/db/operations"
Job Definitions
Jobs are the building blocks of oJob. Each job defines a unit of work.
Basic Job Structure
jobs:
- name: "Basic Job" # unique name (mandatory)
type: simple # Job type (default)
exec: | #js # Code to execute
print("Hello from " + job.name)
args.result = "success"
Job Types
Simple Jobs (default)
jobs:
- name: "Simple Job"
type: simple
exec: | #js
// Your JavaScript code here
log("Processing...")
Periodic Jobs
jobs:
- name: "Scheduled Job"
type: periodic
typeArgs:
cron: "0 */5 * * * *" # Every 5 minutes
# OR
timeInterval: 300000 # Every 5 minutes in ms
waitForFinish: true # Don't start new if previous still running
exec: | #js
log("Periodic execution at " + new Date())
Shutdown Jobs
jobs:
- name: "Cleanup Job"
type: shutdown
exec: | #js
log("Cleaning up before shutdown")
// Cleanup code here
Subscribe Jobs
jobs:
- name: "Channel Subscriber"
type: subscribe
typeArgs:
chSubscribe: "dataChannel"
exec: | #js
log("Channel operation: " + op + " on " + ch)
log("Key: " + stringify(k))
log("Value: " + stringify(v))
External oJob Jobs
jobs:
- name: "External Job Runner"
type: jobs
typeArgs:
file: "external-ojob.yaml"
# OR
url: "https://example.com/remote-ojob.yaml"
Job Dependencies
jobs:
- name: "Dependent Job"
deps:
- "Prerequisite Job"
- name : "Another Prerequisite"
onSuccess: | #js
log("Prerequisite succeeded")
onFail : | #js
log("Prerequisite failed")
return false # Stop execution
exec: | #js
log("All dependencies satisfied")
Job Arguments and Templates
jobs:
- name: "Templated Job"
args:
defaultValue: "hello"
templateValue: "{{args.input}}-processed"
exec: | #js
log("Default: " + args.defaultValue)
log("Template result: " + args.templateValue)
Default Arguments
oJob supports default argument values using the "${key:-defaultValue}" syntax. This allows you to specify fallback values for arguments that may not be provided:
jobs:
- name: "Job with Default Args"
args:
# Use "defaultHost" if "serverHost" is not defined
host: "${serverHost:-defaultHost}"
# Use 8080 if "serverPort" is not defined
port: "${serverPort:-8080}"
# Use existing value if "environment" is provided, otherwise use "development"
env: "${environment:-development}"
# Works with nested paths - use "localhost" if config.database.host is not defined
dbHost: "${config.database.host:-localhost}"
exec: | #js
log("Connecting to: " + args.host + ":" + args.port)
log("Environment: " + args.env)
log("Database host: " + args.dbHost)
todo:
- name: "Job with Default Args"
args:
serverHost: "production.example.com"
config:
database:
host: "db.example.com"
Key features:
- Fallback values: If the specified key is undefined, the default value is used
- Type preservation: Default values are treated as strings but can represent any value
- Nested paths: Supports dot notation for nested object properties (e.g.,
config.database.host) - Circular reference prevention: A key cannot reference itself as a default to prevent infinite loops
- Runtime evaluation: Default values are resolved when arguments are processed before job execution
- String values only: The syntax only works with string values containing the exact pattern
"${key:-default}"
Examples:
"${missingKey:-defaultValue}"->"defaultValue"(ifmissingKeyis undefined)"${existingKey:-defaultValue}"-> value ofexistingKey(ifexistingKeyexists)"${config.timeout:-30000}"->"30000"(ifconfig.timeoutis undefined)"${circularRef:-circularRef}"->"${circularRef:-circularRef}"(prevents circular reference)
Usage contexts: This default argument syntax can be used in:
- Job
argssections - Arguments passed from
fromjobs to current jobs - Any string value within job argument processing
Note: This feature is processed by the __defaultArgs function during argument preparation, which occurs before job execution and when processing job dependencies.
Error Handling
jobs:
- name : "Error Prone Job"
catch: | #js
logErr("Job failed: " + exception)
// Handle error, return false to propagate
return true // Error handled
exec : | #js
if (Math.random() > 0.5) {
throw "Random failure"
}
Job Languages
oJob supports multiple languages beyond JavaScript:
jobs:
# Python
- name: "Python Job"
lang: python
exec: | #python
import json
print("Python is running")
args['pythonResult'] = 'success'
# Shell/Bash
- name: "Shell Job"
lang: shell
exec: | #shell
echo "Running shell command"
# To use input args
# echo $aInputArgs
# OR
# echo {{aInputArgs}}
export RESULT="shell-success"
# To output args
echo '{"shellResult": "'$RESULT'"}'
# SSH Remote
- name : "Remote SSH Job"
lang : ssh
exec : | #shell
echo "Running on remote server"
hostname
typeArgs:
shell: "/bin/bash"
# PowerShell
- name: "PowerShell Job"
lang: powershell
exec: | #powershell
Write-Host "PowerShell is running"
$_args.psResult = "success"
# Python
- name: "Python Job"
lang: python
exec: | #python
print("Python is running")
args['pythonResult'] = 'success'
# Alternative Python execution
- name: "Python File Job"
typeArgs:
execPy: "/path/to/script.py"
exec: |
# Python script will be executed
# Go
- name: "Go Job"
lang: go
exec: | #go
fmt.Println("Go is running")
args["goResult"] = "success"
# Ruby
- name: "Ruby Job"
lang: ruby
exec: | #ruby
puts "Ruby is running"
args['rubyResult'] = 'success'
# Node.js
- name: "Node Job"
lang: node
exec: | #js
console.log("Node.js is running")
args.nodeResult = "success"
If not ‘lang’ entry is provided it’s assumed to be
javascript/oaf/jswhich defaults to OpenAF’s javascript
Job Execution Control
jobs:
- name : "Controlled Job"
typeArgs:
timeout : 30000 # Max execution time (ms)
single : true # Don't parallelize array args
async : false # Force synchronous execution
noLog : true # Don't log this job
pwd : "/tmp" # Working directory
when : ["init", "ready"] # Only run in these states
stopWhen: | # Stop condition
return args.shouldStop == true
lock: "myLock" # Mutual exclusion lock
lockCh: "lockChannel" # Channel for locks
exec : |
// Job code here
Job Validation
oJob provides comprehensive input and output validation through the check section:
jobs:
- name : "Validated Job"
check:
in: # Input validation
inputFile: isString # Must be a string
port : toNumber.isNumber.default(8080) # Convert to number, default 8080
enabled : toBoolean.isBoolean.default(false) # Convert to boolean, default false
config : isMap # Must be an object/map
items : isArray.default([]) # Must be array, default empty
level : isString.oneOf(['debug', 'info', 'warn', 'error']).default('info')
timeout : isNumber.between(1000, 60000).default(30000) # Between 1-60 seconds
out: # Output validation
result: isString.oneOf(['success', 'failure']) # Must be one of these values
count : isNumber.default(0) # Must be number, default 0
data : isMap.default({}) # Must be map, default empty object
exec : | #js
// Input validation happens automatically before this code runs
// args.inputFile is guaranteed to be a string
// args.port is guaranteed to be a number (converted from string if needed)
// args.enabled is guaranteed to be a boolean
// Process the validated inputs
log("Processing file: " + args.inputFile + " on port: " + args.port);
// Set outputs - these will be validated too
args.result = "success"
args.count = 42
args.data = { processed: true, timestamp: new Date() }
// Output validation happens automatically after this code runs
Advanced Validation Examples
jobs:
- name: "Advanced Validation"
check:
in:
# String validations
email : isString.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/) # Email regex
username : isString.minLength(3).maxLength(20) # Length constraints
password : isString.minLength(8).hasUpperCase().hasLowerCase().hasNumber()
# Number validations
age : isNumber.between(0, 150) # Age range
score : isNumber.multipleOf(0.5).between(0, 100) # Score in 0.5 increments
# Array validations
tags : isArray.minLength(1).maxLength(10) # 1-10 items
emails : isArray.eachIsString() # Each item must be string
# Object validations
settings : isMap.hasKeys(['theme', 'language']) # Must have required keys
metadata : isSchema({ # JSON Schema validation
type: "object",
properties: {
version: { type: "string" },
created: { type: "string", format: "date-time" }
},
required: ["version"]
})
# Conditional validation
database : check("args.useDatabase", "isMap.hasKeys(['host', 'port'])")
out:
# Ensure outputs meet requirements
processedCount: isNumber.min(0)
errors : isArray.default([])
status : isString.oneOf(['completed', 'failed', 'partial'])
exec : | #js
// All inputs are validated and converted as needed
args.processedCount = 100
args.status = "completed"
Job Inheritance
jobs:
- name: "Base Job"
exec: | #js
log("Base functionality")
- name: "Extended Job"
from:
- "Base Job" # Execute before main job
to :
- "Cleanup Job" # Execute after main job
exec: | #js
log("Main functionality")
Job Help
jobs:
- name: "Documented Job"
help:
text : "This job processes data files"
expects:
- name: inputFile
desc: "Path to input file"
- name: format
desc: "Output format"
exec: |
// Job implementation
Code Separation
The code section allows separating JavaScript code from job definitions:
code:
utils.js: | #js
exports.processData = function(data) {
return data.map(item => item.toUpperCase())
}
config.json: | #json
{
"apiUrl": "https://api.example.com",
"timeout": 30000
}
jobs:
- name : "Code Using Job"
typeArgs:
execRequire: "utils.js" # Load and call exports.jobName
# Alternative: reference file directly
# typeArgs:
# file: "config.json"
Built-in Jobs
oJob includes many built-in jobs for common operations. These are available when ojob.includeOJob is true (default).
Common Built-in Jobs
Core Execution Jobs:
ojob pass- Placeholder/pass job to allow for arguments injectionojob parallel- Execute jobs in parallelojob if- Conditional execution based on conditionsojob repeat- Repeats sequentially for a specific number of timesojob repeat with each- Repeats for each element in a provided listojob run- Execute a single job with specific argumentsojob run file- Execute external YAML/JSON ojob files or remote URLsojob todo- Execute an ojob sub-todo listojob wait- Wait for a specific amount of timeojob exit- End all processing with an exit code
Data Management Jobs:
ojob get- Retrieve a specific map key or path using $getojob set- Set a key with current value or provided data using $setojob unset- Unset a key using $unsetojob get pm- Get process manager dataojob file get- Retrieve data from YAML or JSON filesojob query- Perform queries using ow.obj.filter on existing argsojob convert- Convert string content into internal objects (map/array)ojob split to items- Split strings into arrays
Output and Logging Jobs:
ojob output- Print current arguments to console with formattingojob print- Print a message line using OpenAF templatesojob print md- Parse and display simple ASCII markdownojob log- Log a message line using OpenAF templatesojob debug- Output current args and res values for debugging
Template and Processing Jobs:
ojob template- Apply OpenAF templates over provided dataojob template folder- Process template folders recursivelyojob find/replace- Perform in-memory find/replace operationsojob function- Execute OpenAF functions dynamicallyojob oafp- OpenAF Processing operations for data transformation
Channel Operations:
ojob channel- Provide operations over OpenAF channels
Security and Environment:
ojob sec get- Get SBucket secrets and map to oJob argsojob set envs- Set job args based on environment variables
State Management:
ojob state- Change the current execution stateojob set state- Set the current stateojob get state- Get the current state into args.state
Interactive and User Input:
ojob ask- Interactive prompts for user inputojob questions- Handle multiple interactive questions
Planning and Validation:
ojob check- Check and validate inputs with actionsojob job- Organize idempotent jobs with checks and actionsojob options- Handle switch/options based execution
AI and Advanced Processing:
ojob llm- Execute LLM (Local Language Model) prompts
Reporting Jobs:
ojob report- Output job execution reportsojob job report- Output job planning reportsojob deps report- Output dependency tree reportsojob final report- Output reports upon ojob terminationojob final deps report- Output dependency reports upon terminationojob job final report- Output job reports upon termination
Built-in Job Shortcuts
oJob provides many built-in shortcuts for common operations:
todo:
# Conditional execution
- (if ): "args.env == 'prod'"
((then)):
- "Production Job"
((else)):
- "Development Job"
# Parallel execution
- (parallel):
- "Job A"
- "Job B"
- "Job C"
# Set values
- (set): myKey
value: "some value"
# Get values
- (get): myKey
# File operations
- (fileget): "config.json"
((out )): config
# Channel operations
- (ch ): "myChannel"
((op)): "set"
((k )): { id: 1 }
((v )): { name: "test" }
# Output formatting
- (output ): results
((format)): "json"
# Template processing
- (template): "Hello {{name}}!"
((data )): { name: "World" }
# Ask for input
- (ask): "Please enter your name"
# Wait/delay
- (wait): 5000 # Wait 5 seconds
# Logging
- (log ): "Processing started"
((level)): "INFO"
# Run external oJob
- (runfile): "external.yaml"
((args )): { param: "value" }
# Repeat operations
- (repeat): 3
((todo)):
- "Repeated Job"
# Each loop
- (each ): "items"
((todo)):
- "Process Item"
# Query data
- (query ): "[?status=='active']"
((from)): "data"
((to )): "activeItems"
# State management
- (state ): "processing"
- (stateOn ): "processing"
((default)): "Continue Processing"
# Debug
- (debug): # Pause for debugging
# Conversion
- (convert ): "inputData"
((outFormat)): "yaml"
((outKey )): "yamlData"
Built-in Jobs and Shortcut Correlation
| Built-in Job | Shortcut Equivalent |
|---|---|
| ojob pass | (pass) |
| ojob parallel | (parallel) |
| ojob if | (if) |
| ojob repeat | (repeat) |
| ojob repeat with each | (each) |
| ojob run | (run) |
| ojob run file | (runfile) |
| ojob todo | (todo) |
| ojob wait | (wait) |
| ojob exit | (fail) |
| ojob get | (get) |
| ojob set | (set) |
| ojob unset | (unset) |
| ojob get pm | |
| ojob file get | (fileget) |
| ojob query | (query) |
| ojob convert | (convert) |
| ojob split to items | (split) |
| ojob channel | (ch) |
| ojob output | (output) |
| ojob print | (print) |
| ojob print md | (printmd) |
| ojob log | (log) |
| ojob template | (template) |
| ojob template folder | (templateFolder) |
| ojob find/replace | (findReplace) |
| ojob function | (fn) |
| ojob oafp | (oafp) |
| ojob sec get | (secget) |
| ojob set envs | (setenvs) |
| ojob state | (state) |
| ojob set state | (state) |
| ojob get state | |
| ojob check | (check) |
| ojob job | |
| ojob options | (options) |
| ojob llm | (llm) |
| ojob report | |
| ojob job report | |
| ojob deps report | |
| ojob final report | |
| ojob final deps report | |
| ojob job final report | |
| ojob ask | (ask) |
| ojob questions | (questions) |
Not all built-in jobs have a direct shortcut equivalent. Shortcuts provide a concise way to invoke common jobs in the
todosection.
To the list of arguments that apply to an shortcut run
ojob -shortcuts ojob something; to get help on each argument runojob -jobhelp ojob something
Built-in Job Arguments Reference
(pass) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __args | (pass) | The args to inject | | __debug | ((debug)) | Boolean to print args before injection | | __templateArgs | ((templateArgs)) | Boolean to apply template to each string in args |
(get) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __key | (get) | Map key to retrieve | | __path | ((path)) | Path to consider from the __key |
(set) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __key | (set) | Map key | | __path | ((path)) | Path to value from current args | | __data | ((data)) | Data to set | | __templateArgs | ((templateArgs)) | Apply template to each entry in __data | | __debug | ((debug)) | Print current args |
(unset) | Argument | Shortcut argument | Description | |—————–|—————————————————————————–| | __key | (unset) | Map key to unset |
(fileget) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __file | (fileget) | File path to YAML/JSON file | | __path | ((path)) | Path of the file contents | | __cache | ((cache)) | Boolean to cache file contents | | __ttl | ((ttl)) | TTL for cache | | __out | ((out)) | Path on args to set contents | | __key | ((key)) | Key to set content if __out not defined |
(template) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | template | (template) | Template string | | templateFile | ((templateFile)) | Template file | | data | ((data)) | Data to use | | dataFile | ((dataFile)) | Data file (yaml/json) | | outputFile | ((outputFile)) | Output file path | | __key | ((key)) | Key holding template/data | | __tpath | ((tpath)) | Path to template | | __dpath | ((dpath)) | Path to data | | __outPath | ((outPath)) | Output path | | __out | ((out)) | Output key |
(templateFolder) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | templateFolder | (templateFolder) | Folder with templates | | __templatePath | ((templatePath)) | Path over recursive list of files | | outputFolder | ((outputFolder)) | Output folder | | data | ((data)) | Data to use | | dataFile | ((dataFile)) | Data file | | __key | ((key)) | Key holding template/data | | __dpath | ((dpath)) | Path to data | | logJob | ((logJob)) | Logging job | | metaTemplate | ((metaTemplate)) | Interpret json/yaml files as argument maps |
(findReplace) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __key | (findReplace) | Key holding replacements | | __path | ((path)) | Path to replacements | | inputKey | ((inputKey)) | Key holding string to replace | | inputPath | ((inputPath)) | Path to string to replace | | inputFile | ((inputFile)) | File to read contents from | | outputFile | ((outputFile)) | File to write output to | | useRegExp | ((useRegExp)) | Interpret replacements as regexp | | flagsRegExp | ((flagsRegExp)) | Regexp flags | | logJob | ((logJob)) | Logging job |
(ch) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __name | (ch) | Channel name | | __op | ((op)) | Operation (set, get, unset, setall, unsetall, getall, getkeys) | | __key | ((key)) | Key for operation args | | __kpath | ((kpath)) | Path for keys | | key | ((k)) | Key for set/get/unset | | keys | ((ks)) | Keys for setall/unsetall | | value | ((v)) | Value for set/get/unset | | values | ((vs)) | Values for setall/unsetall | | __vpath | ((vpath)) | Path for values | | extra | ((extra)) | Extra argument for getall/getkeys |
(print) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | msg | (print) | Message template | | __key | ((key)) | Key to retrieve | | __path | ((path)) | Path to consider from __key | | level | ((level)) | Message level (info/error) |
(printmd) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __text | (printmd) | Text template to parse | | __outputMD | ((outputMD)) | Boolean to output as markdown |
(log) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | msg | (log) | Message template | | __key | ((key)) | Key to retrieve | | __path | ((path)) | Path to consider from __key | | level | ((level)) | Message level (info/warn/error) | | options | ((options)) | Extra options for log functions |
(fn) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __fn | (fn) | Function to execute | | __key | ((key)) | Key to retrieve previous results | | __path | ((path)) | Path for function arguments | | __fnPath | ((fnPath)) | Path to set function result |
(output) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __key | (output) | Key to retrieve results | | __path | ((path)) | Path to map/array over results | | __format | ((format)) | Output format | | __title | ((title)) | Title key for output | | __internal | ((internal)) | Show internal oJob entries | | __function | ((function)) | Print/log function |
(todo) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | todo | (todo) | String or array of todo maps | | isolateArgs | ((isolateArgs)) | Isolate args from all others | | isolateJob | ((isolateJobs)) | Run job in different scope | | templateArgs | ((templateArgs)) | Apply template to each string in args | | shareArgs | ((shareArgs)) | Share args between jobs sequentially | | __debug | ((debug)) | Print job execution parameters |
(runfile) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __job | (runfile) | YAML/JSON ojob file or remote URL | | __args | ((args)) | Args to provide to external ojob | | __out | ((out)) | Path on args to set contents | | __key | ((key)) | Key to set content if __out not defined | | __inKey | ((inKey)) | Merge args with content from provided key | | __usePM | ((usePM)) | Output to __pm | | __inPM | ((inPM)) | Input from provided key to __pm | | __templateArgs | ((templateArgs)) | Apply template to each string in args | | __debug | ((debug)) | Print job execution parameters |
(parallel) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | todo | (parallel) | String or array of todo maps | | isolateArgs | ((isolateArgs)) | Isolate args from all others | | isolateJob | ((isolateJob)) | Run job in different scope | | templateArgs | ((templateArgs)) | Apply template to each string in args | | shareArgs | ((shareArgs)) | Share args between jobs sequentially | | isolateArgs | on each entry | Isolate args from all others only on this entry | | isolateJob | on each entry | Run job in different scope only on this entry | | templateArgs | on each entry | Apply template to each string in args only on this entry | | shareArgs | on each entry | Share args between jobs sequentially only on this entry | | __debug | ((debug)) | Print job execution parameters |
(wait) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | time | ((wait)) | Amount of time in ms to pause execution |
(fail) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | code | (fail) | Exit code number | | force | ((force)) | Boolean to halt processing instead of exit |
(convert) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __inKey | (convert) | Input key for contents to convert | | __inPath | ((inPath)) | Path on input contents | | __inFormat | ((inFormat)) | Format of input contents (yaml, json, xml, ndjson, slon) | | __outKey | ((outKey)) | Output key for converted object | | __outPath | ((outPath)) | Path on output contents |
(questions) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __questions | (questions) | Map structure for askStruct |
(ask) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __question | (ask) | Question to ask | | __answers | ((answers)) | Map of answers to store into args | | __force | ((force)) | Force asking even if value is defined |
(oafp) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __params | (oafp) | Parameters to provide to oafp |
(llm) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __llmPrompt | (llm) | Prompt to send to LLM model | | __llmContext | ((context)) | Context of input data | | __llmInPath | ((inPath)) | Path to consider from __llmInKey | | __llmInKey | ((inKey)) | Key for input data | | __llmEnv | ((env)) | Environment variable for $llm options | | __llmOptions | ((options)) | Options for $llm | | __llmOutPath | ((outPath)) | Path to store result | | __llmDebug | ((debug)) | Print job execution parameters |
(secget) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | secKey | (secget) | SBucket key | | secRepo | ((secRepo)) | SBucket repository | | secBucket | ((secBucket)) | SBucket name | | secPass | ((secPass)) | SBucket password | | secOut | ((secOut)) | Args path to map secret | | secMainPass | ((secMainPass)) | SBucket repository password | | secFile | ((secFile)) | SBucket file | | secDontAsk | ((secDontAsk)) | Don’t ask for passwords | | secIgnore | ((secIgnore)) | Ignore errors for missing sec parameters | | secEnv | ((secEnv)) | Retrieve secret from env variable |
(query) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __query | (query) | Query map for ow.obj.filter or af.fromNLinq | | __type | ((type)) | Type of query (path, sql, nlinq) | | __from | ((from)) | Path to args key to query | | __to | ((to)) | Path to store results in args | | __toKey | ((toKey)) | Key to set results | | __key | ((key)) | Key for input/output |
(optionOn) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __optionOn | (optionOn) | Variable in args to define which todos to add | | __lowerCase | ((lowerCase)) | Compare optionOn in lower case | | __upperCase | ((upperCase)) | Compare optionOn in upper case | | __todos | ((todos)) | Map of option values to todo arrays | | __default | ((default)) | Default array of todos | | __async | ((async)) | Run todos in async mode |
(state) | Argument | Shortcut argument | Description | |—————–|——————-|—————————————————————————–| | __state | (state) | State to change to |
Examples
todo:
# Security operations
- (secget ): "mySecretKey"
((secRepo )): "secrets"
((secBucket)): "app-secrets"
# Print markdown
- (printmd): |
# Status Report
Current status: {{status}}
# Function execution
- (fn ): "myFunction"
((args)): { param: "value" }
# Split operations
- (split ): "item1,item2,item3"
((sep )): ","
((outPath)): "items"
# Options/switch operations
- (options): "environment"
((dev )):
- "Development Job"
((prod )):
- "Production Job"
# Environment variable setting
- (setenvs):
DATABASE_URL: "{{config.db.url}}"
API_KEY: "{{secrets.apikey}}"
# Job planning and checking
- (check ): "Validation Job"
((actions)):
create: "Create Resource"
update: "Update Resource"
# Find and replace operations
- (replace ): "input text"
((replace)): "old"
((with )): "new"
((outPath)): "result"
# OAFP (OpenAF Processing) operations
- (oafp ): "data"
((from )): "json"
((to )): "yaml"
((outPath)): "convertedData"
Example 1: Basic Hello World
help:
text: "A simple Hello World example"
jobs:
- name: "Hello World"
exec: |
print("Hello, World!")
Example 2: File Processing with Arguments
help:
text: "Processes a file and outputs results"
expects:
- name: inputFile
desc: "The file to process"
- name: outputDir
desc: "Where to save the results"
init:
outputDir: "/tmp/results"
ojob:
logToConsole: true
jobs:
- name: "Process File"
exec: |
var lines = readFile(args.inputFile).split("\n");
var result = lines.length;
writeFile(args.outputDir + "/result.txt", "Line count: " + result);
Example 3: Conditional Execution
help:
text: "Runs different jobs based on the environment"
jobs:
- name: "Setup"
exec: |
if (args.env == "prod") {
// Production setup
} else {
// Development setup
}
Example 4: Parallel Job Execution
help:
text: "Processes multiple files in parallel"
jobs:
- name: "List files"
from:
- (pass ):
aFilePath: "."
- (fn ): io.listFiles
((key )): res
each:
- Process file
exec: | #js
$get("res").files.forEach(file => {
print(`gear Processing file ${file.canonicalPath}...`)
// Executes the array of jobs defined in the 'each' parameter with the 'file' map
each(file)
})
- name: Process file
exec: | #js
print(` [file] file ${args.canonicalPath} with ${args.size} bytes processed.`)
The each section allows a job to call other jobs in parallel for each element in a list or array:
Example 5: Using Templates
help:
text: "Demonstrates the use of templates in oJob"
jobs:
- name: "Generate Config"
args:
env: "production"
exec: |
var template = "server {\n listen 80;\n server_name {{domain}};\n}\n";
var data = { domain: "example.com" };
var config = templify(template, data);
writeFile("/etc/nginx/conf.d/example.com.conf", config);
Example 6: Error Handling
help:
text: "Shows how to handle errors in oJob"
jobs:
- name: "Faulty Job"
catch: | #js
logErr("Job failed: " + exception)
// Handle error, return false to propagate
return true // Error handled
exec : | #js
if (Math.random() > 0.5) {
throw "Random failure"
}
Example 6.5: Default Arguments
help:
text: "Demonstrates default argument values"
expects:
- name: environment
desc: "Environment to deploy to (dev, staging, prod)"
example: "dev"
- name: database_host
desc: "Database server hostname"
example: "db.example.com"
- name: api_port
desc: "Port for the API server"
example: "3000"
jobs:
- name: "Configuration Setup"
args:
# Environment defaults to "development" if not provided
env: "${environment:-development}"
# Database connection with nested path fallback
dbHost: "${config.database.host:-localhost}"
dbPort: "${config.database.port:-5432}"
dbName: "${config.database.name:-myapp}"
# API configuration with fallbacks
apiPort: "${api_port:-3000}"
apiHost: "${api_host:-0.0.0.0}"
# Service URLs with environment-based defaults
logServiceUrl: "${log_service_url:-http://localhost:8080/logs}"
# Feature flags with boolean defaults
enableDebug: "${debug_mode:-false}"
exec: | #js
log("Environment: " + args.env)
log("Database: " + args.dbHost + ":" + args.dbPort + "/" + args.dbName)
log("API Server: " + args.apiHost + ":" + args.apiPort)
log("Log Service: " + args.logServiceUrl)
log("Debug Mode: " + args.enableDebug)
// Configuration object for other jobs to use
args.config = {
environment: args.env,
database: {
host: args.dbHost,
port: parseInt(args.dbPort),
name: args.dbName
},
api: {
host: args.apiHost,
port: parseInt(args.apiPort)
},
services: {
logging: args.logServiceUrl
},
features: {
debug: args.enableDebug === "true"
}
}
todo:
- name: "Configuration Setup"
args:
# Only provide some values, others will use defaults
environment: "staging"
api_port: "4000"
config:
database:
host: "staging-db.example.com"
name: "staging_myapp"
Example 7: Using Multiple Languages
help:
text: "Demonstrates using different languages in jobs"
jobs:
# Python
- name: "Python Job"
lang: python
exec: | #python
import json
print("Python is running")
args['pythonResult'] = 'success'
# Shell/Bash
- name: "Shell Job"
lang: shell
exec: | #shell
echo "Running shell command"
# To use input args
# echo $aInputArgs
# OR
# echo {{aInputArgs}}
export RESULT="shell-success"
# To output args
echo '{"shellResult": "'$RESULT'"}'
# SSH Remote
- name : "Remote SSH Job"
lang : ssh
exec : | #shell
echo "Running on remote server"
hostname
typeArgs:
shell: "/bin/bash"
# PowerShell
- name: "PowerShell Job"
lang: powershell
exec: | #powershell
Write-Host "PowerShell is running"
$_args.psResult = "success"
# Go
- name: "Go Job"
lang: go
exec: | #go
fmt.Println("Go is running")
args["goResult"] = "success"
# Ruby
- name: "Ruby Job"
lang: ruby
exec: | #ruby
puts "Ruby is running"
args['rubyResult'] = 'success'
# Node.js
- name: "Node Job"
lang: node
exec: | #js
console.log("Node.js is running")
args.nodeResult = "success"
Example 8: Job Dependencies
help:
text: "Demonstrates job dependencies"
jobs:
- name: "Main Job"
deps:
- "Setup Job"
- name : "Config Job"
onSuccess: | #js
log("Config loaded")
onFail : | #js
log("Config failed")
return false # Stop execution
exec: | #js
log("All dependencies satisfied")
Example 9: Job Each Processing
jobs:
# Example: Process multiple files in parallel
- name: List files to process
from:
- (pass ):
aFilePath: "."
- (fn ): io.listFiles
((key )): res
each:
- Process file
exec: | #js
$get("res").files.forEach(file => {
print(`gear Processing file ${file.canonicalPath}...`)
// Executes the array of jobs defined in the 'each' parameter with the 'file' map
each(file)
})
- name: Process file
exec: | #js
print(` [file] file ${args.canonicalPath} with ${args.size} bytes processed.`)
The each functionality:
- Calls the specified jobs in parallel
- Passes the current arguments as the
each(data)parameter - Each call receives the data passed to the
each()function - Useful for parallel processing of collections
Example 10: State Management
todo:
- (state): "initializing"
- name : "State Dependent Job"
when : "initializing"
- (state): "processing"
- name : "Processing Job"
when : "processing"
Example 11: Metrics Collection
ojob:
metrics:
add:
processedItems: | #js
return { count: $get("processedCount") || 0 }
jobs:
- name: "Metric Updating Job"
exec: | #js
ow.oJob.setMetric("processedItems", {
type: "processedItems",
count: args.itemCount
})
Example 12: Channel Operations
jobs:
- name: "Channel Writer"
exec: | #js
$ch("dataChannel").set(
{ id: args.id },
{ data: args.data, timestamp: now() }
)
- name: "Channel Reader"
exec: | #js
var data = $ch("dataChannel").getAll()
args.results = data
Example 13: Template Processing
jobs:
- name: "Template Job"
exec: | #js
var template = "Hello {{name}}, welcome to {{app}}!"
var data = { name: args.userName, app: "oJob" }
args.message = templify(template, data)
Example 14: Job Shortcut Support
oJob supports shortcut definitions that create convenient shorthand syntax for jobs:
jobs:
- name : "My Custom Job"
typeArgs:
shortcut:
name : "mycustom" # Creates (mycustom) shortcut
keyArg: "inputValue" # Main argument for the shortcut
args : # Mapping of shortcut args to job args
output: "__output" # Creates ((output)) shortcut arg
format: "__format" # Creates ((format)) shortcut arg
exec : | #js
// Job logic here
- Adding a shortcut to an existing job
- Add a
typeArgs.shortcutmap to the job you want to expose through shortcut syntax. - Set
nameto the identifier that will become(name)in thetodolist. - Use
keyArgwhen you want the unnamed value after(name)to feed a specific job argument. - Map each named shortcut argument
((arg))to the underlying job argument in theargsmap. - Configure optional fields such as
nolog: trueto inherit additional behaviour.
Refer to the oJob full template for the complete structure of
typeArgs.shortcut, including optional fields such asnologand detailed comments about each entry. A practical shortcut example lives in the oJob Building Blocks guide where the(pass)shortcut maps its__args,__debug, and__templateArgsparameters so they can be provided directly from shortcut notation. - Add a
Usage in todo:
todo:
- (mycustom): "input data"
((output)): "result"
((format)): "json"
Example 15: Job Security Features
jobs:
- name: "Secure Job"
exec: | #js
// Access secure data using SBucket
var secret = $sec("mysecrets", "mypassword").get("apikey")
todo:
- (secget ): "database.password"
((secRepo )): "myrepo"
((secBucket)): "secrets"
Example 16: Job Markdown Support
todo:
- (printmd ): | #handlebars
# Status Report
Processing completed with {{results.count}} items.
## Results:
{{#each results.items}}
- **{{name}}**: {{status}}
{{/each}}
((outputMD)): false # Parse as markdown (default)
Example 17: Job LLM Integration
jobs:
- name: "AI Analysis"
exec: | #js
var prompt = "Analyze this data and provide insights"
var result = $llm().withContext(args.data, "sales data").promptJSON(prompt)
args.analysis = result
todo:
- (llm ): "Summarize the following data in 3 bullet points"
((inKey )): "salesData"
((inPath )): "records"
((context)): "monthly sales figures"
((outPath)): "summary"
Use the OAF_MODEL environment variable to specify the LLM model to use similarily to OAFP_MODEL
Example 18: Job State Management
jobs:
- name : "State Dependent Job"
typeArgs:
when: ["processing", "ready"] # Only run in these states
exec : |
// This job only runs when state is 'processing' or 'ready'
todo:
- (state): "initializing"
- "Setup Job"
- (state): "processing"
- "State Dependent Job"
Example 19: Additional Built-in Jobs
todo:
# Security operations
- (secget ): "mySecretKey"
((secRepo )): "secrets"
((secBucket)): "app-secrets"
# Print markdown
- (printmd ): |
# Status Report
Current status: {{status}}
# Function execution
- (fn ): "myFunction"
((args)): { param: "value" }
# Split operations
- (split ): "item1,item2,item3"
((sep )): ","
((outPath)): "items"
# Options/switch operations
- (options): "environment"
((dev )):
- "Development Job"
((prod )):
- "Production Job"
# Environment variable setting
- (setenvs):
DATABASE_URL: "{{config.db.url}}"
API_KEY: "{{secrets.apikey}}"
# Job planning and checking
- (check ): "Validation Job"
((actions)):
create: "Create Resource"
update: "Update Resource"
# Find and replace operations
- (replace ): "input text"
((replace)): "old"
((with )): "new"
((outPath)): "result"
# OAFP (OpenAF Processing) operations
- (oafp ): "data"
((from )): "json"
((to )): "yaml"
((outPath)): "convertedData"
Example 20: Advanced Monitoring and Metrics
ojob:
daemon: true
metrics:
active :
nattrmon:
url : "http://monitor:7777/remote"
attrPrefix: "DataPipeline/"
periodInMs: 30000
collect:
ch : "metricsHistory"
period: 10000
some : ["mem", "cpu", "custom-throughput"]
add :
custom-throughput: | #js
return {
value: $get("processedFiles") || 0,
timestamp: now()
}
jobs:
- name : "Health Check"
type : periodic
typeArgs:
cron : "*/30 * * * * *" # Every 30 seconds
cronCheck: |
return ow.oJob.getState() === "running"
exec : | #js
var health = {
status: "healthy",
uptime: now() - $get("startTime"),
processed: $get("processedFiles") || 0
}
$ch("health").set("current", health)
- name : "Cleanup Old Files"
type : periodic
typeArgs:
cron: "0 0 2 * * *" # Daily at 2 AM
exec : | #js
var cutoff = now() - (7 * 24 * 60 * 60 * 1000) # 7 days ago
// Cleanup logic here
todo:
- (state): "running"
- "Health Check"
- "Cleanup Old Files"
Example 21: Cron Reliability & Retries (cronCheck)
Periodic jobs can recover missed runs & retry failures using typeArgs.cronCheck.
jobs:
- name : Sample Periodic
type : periodic
typeArgs:
cron : "*/15 * * * * *"
waitForFinish: true
cronCheck :
active : true
ch : oJob::cron
retries : 3
retryWait: 2000
exec : | #js
if (Math.random() < 0.2) throw "transient error";
log("OK " + new Date())
Channel schema per job: { name, last, status, retries }.
Example 22: Integrity, Auditing & Change Detection
Provide hashes to detect tampering and enable auditing flags:
ojob:
integrity:
list:
- dep.yaml: sha256:abcd...
warn: true
Set env OJOB_CHECK_JOB_CHANGES=true / OJOB_CHECK_JOB_REMOVAL=true for dynamic mutation warnings.
Example 23: Environment Variable Injection
ojob.argsFromEnvs: true converts all environment variables to args (lowercased + underscores). Use initTemplateEscape: true to preserve literal handlebars in init.
Example 24: Global vs Job catch
ojob.catch defines a fallback error handler (vars: exception, job, args, id). Individual jobs can also declare catch: overriding it.
Example 25: Unique Execution Control
ojob:
unique:
pidFile : service.pid
killPrevious: true
Rejects concurrent instances (or replaces prior if killPrevious). Runtime control args: stop, restart, forcestop, status.
Example 26: Channel Exposure Auditing
ojob.channels.audit: true (or template string) logs HTTP channel operations with key & user info.
Example 27: Structured JSON Logs
Enable with env OJOB_JSONLOG=true or:
ojob:
log:
format: json
Example 28: cronInLocalTime
ojob.cronInLocalTime: true evaluates cron schedules using local timezone.
Example 29: Code Embedding Precedence
When a file name exists under code: its content overrides filesystem counterparts for execFile / execRequire resolution, enabling fully self-contained distributions.
Example 30: Arg Parallelism Control
Array args run in parallel unless typeArgs.single: true or global numThreads <= 1. Use for rate-limited APIs or ordered processing.
Example 31: Timeout & stopWhen
typeArgs.timeout enforces a max duration; if exceeded an exception is raised. typeArgs.stopWhen (function) is evaluated on timeout to allow graceful termination.
Example 32: Locks (lock / lockCh)
Mutual exclusion across async jobs sharing the same typeArgs.lock name; defaults to channel oJob::locks. Customize storage via lockCh for distributed scenarios.
Example 33: Inspect Internal Job Log
print($ch('oJob::log').getAll())
Example 34: Flag Overrides in YAML
ojob:
flags:
OJOB_CHECK_JOB_CHANGES: true
OJOB_CHECK_JOB_REMOVAL: true
See the Flags Cheat Sheet for an exhaustive list.