Rework job runner to support ext_job_cache for all functions

And try to use more clients-- instead of relying on copy-pasting code from master.py :)

This is me starting down the master_ext_job_cache path (which seems messy- but doable!)