Skip to content

progress: one local page for every background job

The problem

Run more than two background jobs and you stop knowing what any of them did. Each has a log, a notes file and a repo; finding out means opening all three for every job. Most dashboards need a build step, a database and a process you must remember to restart after each change, and a page on a local port can leak files to any web page that knows how to reach it.

The method

The job folders are already the database, so the page reads them fresh on every load.

  • No state of its own. Each request reads STATE.md ("Ready" and "Next"), the newest journal note, the wake count, commits since the job's first log and the newest pictures. The open tab reloads every minute.
  • Started once, reused. The command asks the port who is there: this page for these folders, open it; nothing, start a detached server and wait for it; this page for other folders, refuse plainly.
  • Restarts itself on new code. The server outlives the command, so it watches its own file and re-executes itself in place when it changes.
  • Fenced pictures. Served only if, after symlinks and .. resolve, they sit inside a job folder and have a picture extension.
  • Localhost only, twice. Binds 127.0.0.1 and refuses any Host header that is not localhost, so a page that rebinds its domain to 127.0.0.1 still fails.

Sample

The two guards, in Python:

def servable(p, roots):
    p = p.resolve()                                   # symlinks and '..' gone
    return p.suffix.lower() in PICS and p.is_file() and any(p.is_relative_to(r) for r in roots)

def serve(port, dirs):
    born = ME.stat().st_mtime_ns
    start_server_thread(port, dirs)
    while ME.stat().st_mtime_ns == born:
        time.sleep(2)
    os.execv(sys.executable, [sys.executable, str(ME), "--serve", str(port), *dirs])

Use it:

progress ~/jobs                  # every subfolder with a STATE.md
# http://127.0.0.1:4747/
progress page ~/jobs > now.html  # once, no server

Limits

  • Every load reads every folder and runs git log per repo: fine for tens of jobs, not hundreds.
  • It shows; it never starts or stops a job, so no request can make it run anything.
  • Minimal Markdown: text, code, bold, line breaks.

Code

methods/progress/ in the methods repository: the script, a README and a test.