Your First Job¶
Let's start with the simplest possible Job: running a function once.
The Basics¶
A Job wraps your function to provide execution tracking, logging, and output storage.
from examples.common.functions import hello
from runnable import PythonJob
def main():
job = PythonJob(function=hello)
job.execute()
return job # REQUIRED: Always return the job object
if __name__ == "__main__":
main()
See complete runnable code
"""
You can execute this pipeline by:
python examples/01-tasks/python_tasks.py
The stdout of "Hello World!" would be captured as execution
log and stored in the catalog.
An example of the catalog structure:
.catalog
└── baked-heyrovsky-0602
└── hello.execution.log
2 directories, 1 file
The hello.execution.log has the captured stdout of "Hello World!".
"""
from examples.common.functions import hello
from runnable import PythonJob
def main():
job = PythonJob(function=hello)
job.execute()
return job
if __name__ == "__main__":
main()
Try it now:
Always Return the Job Object
Your main() function must return the job object. This is required for:
- Execution tracking - Runnable needs the job object to track execution status
- Metadata access - The returned object contains run IDs, execution logs, and results
- Integration compatibility - External tools expect the job object for further processing
- Debugging support - Access to execution context and error details
❌ Without return:
def main():
job = PythonJob(function=hello)
job.execute()
# Missing return - breaks Runnable's execution model!
✅ Correct pattern:
What Happens When You Run It¶
1. Rich Context Display
🏃 Lets go!!
Working with context:
JobContext(
run_id='null-panini-0628',
catalog=FileSystemCatalog(catalog_location='.catalog'),
job_executor=LocalJobExecutor(),
...
)
2. Function Execution
3. Automatic Storage
- Execution logs captured in
catalog - Unique run ID generated for tracking
- All output preserved automatically
4. Summary Report
Generated Run IDs¶
Each execution gets a unique, memorable run ID:
- null-panini-0628
- minty-brattain-0628
- feasible-booth-0628
These organize your catalog and make runs easy to find.
Custom Run IDs¶
Control execution tracking with custom identifiers:
# Set custom run ID for tracking and debugging
export RUNNABLE_RUN_ID="experiment-learning-rate-comparison-v1"
uv run training_job.py
Benefits:
- Easy identification in logs and run history
- Consistent naming across related executions
- Better debugging when tracking specific experiments
- Integration with external systems using predictable IDs
# Example: A/B testing with clear run IDs
export RUNNABLE_RUN_ID="model-comparison-baseline-v1"
uv run baseline_job.py
export RUNNABLE_RUN_ID="model-comparison-experimental-v1"
uv run experimental_job.py
Default vs Custom Run IDs
Without RUNNABLE_RUN_ID: Auto-generated names like null-panini-0628
With RUNNABLE_RUN_ID: Your custom identifier experiment-learning-rate-comparison-v1
Job Types at a Glance¶
| Job Type | Purpose | Example Use |
|---|---|---|
| PythonJob | Execute Python functions | Data analysis, calculations |
| ShellJob | Run shell commands | File processing, system ops |
| NotebookJob | Execute Jupyter notebooks | Interactive analysis, reports |
What's Next?¶
Now that you can run basic Jobs:
- Working with Data - Store and return function outputs
- Parameters & Environment - Configure Jobs without code changes
- File Storage - Automatically archive Job outputs
Ready to return data from your Jobs? Continue to Working with Data!