fix: feat: task dispatcher — poll ops repo and launch runners (#45)
This commit is contained in:
parent
fb4ffe9fb6
commit
c9ef5eb98b
1 changed files with 127 additions and 7 deletions
128
docker/edge/dispatcher.sh
Normal file → Executable file
128
docker/edge/dispatcher.sh
Normal file → Executable file
|
|
@ -1,12 +1,132 @@
|
|||
#!/usr/bin/env bash
|
||||
# dispatcher.sh — Edge task dispatcher placeholder
|
||||
# dispatcher.sh — Edge task dispatcher
|
||||
#
|
||||
# TODO: Implement task polling and runner launching (#45)
|
||||
# Currently a no-op loop for future expansion.
|
||||
# Polls the ops repo for approved actions and launches task-runner containers.
|
||||
# Part of #24.
|
||||
#
|
||||
# Action JSON schema:
|
||||
# {
|
||||
# "id": "publish-skill-20260328",
|
||||
# "formula": "clawhub-publish",
|
||||
# "secrets": ["CLAWHUB_TOKEN"],
|
||||
# "tools": ["clawhub"],
|
||||
# "context": "SKILL.md bumped to 0.3.0",
|
||||
# "model": "sonnet"
|
||||
# }
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Resolve script root (parent of lib/)
|
||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
# Source shared environment
|
||||
source "${SCRIPT_ROOT}/../lib/env.sh"
|
||||
|
||||
# Ops repo location (vault/actions directory)
|
||||
OPS_REPO_ROOT="${OPS_REPO_ROOT:-/home/debian/disinto-ops}"
|
||||
VAULT_ACTIONS_DIR="${OPS_REPO_ROOT}/vault/actions"
|
||||
|
||||
# Log function
|
||||
log() {
|
||||
printf '[%s] %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*"
|
||||
}
|
||||
|
||||
# Clone or pull the ops repo
|
||||
ensure_ops_repo() {
|
||||
if [ ! -d "${OPS_REPO_ROOT}/.git" ]; then
|
||||
log "Cloning ops repo from ${FORGE_OPS_REPO}..."
|
||||
git clone "${FORGE_WEB}" "${OPS_REPO_ROOT}"
|
||||
else
|
||||
log "Pulling latest ops repo changes..."
|
||||
(cd "${OPS_REPO_ROOT}" && git pull --rebase)
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if an action has already been completed
|
||||
is_action_completed() {
|
||||
local id="$1"
|
||||
[ -f "${VAULT_ACTIONS_DIR}/${id}.result.json" ]
|
||||
}
|
||||
|
||||
# Launch a runner for the given action ID
|
||||
launch_runner() {
|
||||
local id="$1"
|
||||
log "Launching runner for action: ${id}"
|
||||
|
||||
# Read action config
|
||||
local action_file="${VAULT_ACTIONS_DIR}/${id}.json"
|
||||
if [ ! -f "$action_file" ]; then
|
||||
log "ERROR: Action file not found: ${action_file}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract formula from action JSON
|
||||
local formula
|
||||
formula=$(jq -r '.formula // empty' "$action_file")
|
||||
if [ -z "$formula" ]; then
|
||||
log "ERROR: Action ${id} missing 'formula' field"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract secrets (as space-separated list for env injection)
|
||||
local secrets
|
||||
secrets=$(jq -r '.secrets[]? // empty' "$action_file" 2>/dev/null | tr '\n' ' ')
|
||||
|
||||
# Run the formula via docker compose with action ID as argument
|
||||
# The runner container should be defined in docker-compose.yml
|
||||
# Secrets are injected via -e flags
|
||||
local compose_cmd="docker compose run --rm runner ${formula} ${id}"
|
||||
|
||||
if [ -n "$secrets" ]; then
|
||||
# Inject secrets as environment variables
|
||||
for secret in $secrets; do
|
||||
compose_cmd+=" -e ${secret}=${!secret}"
|
||||
done
|
||||
fi
|
||||
|
||||
log "Running: ${compose_cmd}"
|
||||
eval "${compose_cmd}"
|
||||
|
||||
log "Runner completed for action: ${id}"
|
||||
}
|
||||
|
||||
# Main dispatcher loop
|
||||
main() {
|
||||
log "Starting dispatcher..."
|
||||
log "Polling ops repo: ${VAULT_ACTIONS_DIR}"
|
||||
|
||||
# Ensure ops repo is available
|
||||
ensure_ops_repo
|
||||
|
||||
while true; do
|
||||
# Placeholder: no-op loop, no logic yet
|
||||
# Check if actions directory exists
|
||||
if [ ! -d "${VAULT_ACTIONS_DIR}" ]; then
|
||||
log "Actions directory not found: ${VAULT_ACTIONS_DIR}"
|
||||
sleep 60
|
||||
continue
|
||||
fi
|
||||
|
||||
# Process each action file
|
||||
for action_file in "${VAULT_ACTIONS_DIR}"/*.json; do
|
||||
# Handle case where no .json files exist
|
||||
[ -e "$action_file" ] || continue
|
||||
|
||||
local id
|
||||
id=$(basename "$action_file" .json)
|
||||
|
||||
# Skip if already completed
|
||||
if is_action_completed "$id"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Launch runner for this action
|
||||
launch_runner "$id"
|
||||
done
|
||||
|
||||
# Wait before next poll
|
||||
sleep 60
|
||||
done
|
||||
}
|
||||
|
||||
# Run main
|
||||
main "$@"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue