aoh

A tool for running Ansible playbooks with `curl <url> | python` commands
git clone https://git.ashermorgan.net/aoh/
Log | Files | Refs | README

commit e94ed3eb739f36265e7126b3469a12dbc8920a76
parent a1a4b9ccebaa9c9635edaa8449975f0e064cc222
Author: Asher Morgan <asher@ashermorgan.net>
Date:   Tue, 20 Oct 2026 07:16:44 -0700

Add public AOH_GC_{INTERVAL,THRESHOLD} config vars

The ability to control this timing will be useful for future e2e tests.

Diffstat:
MREADME.md | 7+++++++
Maoh/config.py | 18++++++++++++++++++
Maoh/server.py | 15++++++++-------
3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/README.md b/README.md @@ -118,6 +118,13 @@ variables. - `AOH_DEBUG`: If set to `1`, the AoH server will copy `ansible-playbook` output to the server's stdout. Defaults to `0`. +- `AOH_GC_INTERVAL`: The interval on which to clean up exited runners, in + seconds. Defaults to `60`. + +- `AOH_GC_THRESHOLD`: The delay after a runner exits before is may be cleaned + up, in seconds. This delay exists so that clients have time to fetch the final + lines of Ansible output. Defaults to `60`. + - `AOH_LOG_LEVEL`: The threshold for AoH logs, which are written to the server's stdout. Must be one of `CRITICAL`, `ERROR`, `WARNING`, `INFO`, or `DEBUG`. Defaults to `ERROR`. diff --git a/aoh/config.py b/aoh/config.py @@ -11,6 +11,24 @@ load_dotenv() AOH_DEBUG = (os.getenv('AOH_DEBUG', '0') == '1') +try: + AOH_GC_INTERVAL = int(os.getenv('AOH_GC_INTERVAL', '60')) +except ValueError: + logger.critical('$AOH_GC_INTERVAL must be a non-negative integer') + sys.exit(1) +if AOH_GC_INTERVAL < 0: + logger.critical('$AOH_GC_INTERVAL must be a non-negative integer') + sys.exit(1) + +try: + AOH_GC_THRESHOLD = int(os.getenv('AOH_GC_THRESHOLD', '60')) +except ValueError: + logger.critical('$AOH_GC_THRESHOLD must be a positive integer') + sys.exit(1) +if AOH_GC_THRESHOLD <= 0: + logger.critical('$AOH_GC_THRESHOLD must be a positive integer') + sys.exit(1) + AOH_LOG_LEVEL = os.getenv('AOH_LOG_LEVEL', 'ERROR') try: diff --git a/aoh/server.py b/aoh/server.py @@ -4,7 +4,12 @@ import os from flask import Flask, abort, render_template, request, session from flask_apscheduler import APScheduler -from aoh.config import AOH_MAX_RUNNERS, AOH_ORIGIN +from aoh.config import ( + AOH_GC_INTERVAL, + AOH_GC_THRESHOLD, + AOH_MAX_RUNNERS, + AOH_ORIGIN, +) from aoh.playbook import PlaybookFileError, get_playbook from aoh.runner import Runner, RunnerError from aoh.security import ( @@ -16,10 +21,6 @@ from aoh.security import ( _RUNNERS = {} -# Every 60s, tear down runners that finished more than 60s ago -_GC_INTERVAL = 60 -_GC_THRESHOLD = 60 - app = Flask(__name__) app.secret_key = os.urandom(16) @@ -29,13 +30,13 @@ scheduler.init_app(app) logger = logging.getLogger(__name__) -@scheduler.task('interval', seconds=_GC_INTERVAL) +@scheduler.task('interval', seconds=AOH_GC_INTERVAL) def gc(): """Tear down and delete timed-out runners.""" runners = list(_RUNNERS.items()) for id, runner in runners: - if runner and runner.has_timed_out(_GC_THRESHOLD): + if runner and runner.has_timed_out(AOH_GC_THRESHOLD): logger.info(f'{runner.playbook.name} (#{id[:8]}): Runner torn down ' 'due to inactivity') runner.teardown()