Say when a scheduled task is running
Build App (Preview) / compute-version (pull_request) Successful in 7s
Build Container / build-container (pull_request) Successful in 2m53s
Build App (Preview) / create-release (pull_request) Successful in 5s
Build App (Preview) / build-macos (pull_request) Successful in 2m37s
Build App (Preview) / build-windows (pull_request) Successful in 6m2s
Build App (Preview) / build-linux (pull_request) Successful in 6m53s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
Build App (Preview) / compute-version (pull_request) Successful in 7s
Build Container / build-container (pull_request) Successful in 2m53s
Build App (Preview) / create-release (pull_request) Successful in 5s
Build App (Preview) / build-macos (pull_request) Successful in 2m37s
Build App (Preview) / build-windows (pull_request) Successful in 6m2s
Build App (Preview) / build-linux (pull_request) Successful in 6m53s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
A run is detached — cron has no terminal, and the app fires it as a detached exec — so triggering one and watching the log was indistinguishable from triggering one that died. Worse, `claude -p` writes its answer in a single burst at the end, so a healthy run shows nothing but its log header for as long as it is thinking. The honest reading of the old UI was "it stalled". triple-c-task-runner now publishes a state file per run (pid, start time, log path) and removes it from an EXIT trap. flock remains what actually prevents overlapping runs; this is purely observability, so every reader verifies the pid rather than trusting the file — a container stopped mid-run cannot fire a trap, and a task stuck on "running" forever would be a worse lie than no indicator at all. Stale files are cleared on read. On top of that: - `list` grows a status column: "running 4m12s" or "idle". - `status [--id] [--watch]` answers "is it still going?" directly, with elapsed time and the tail of the log when there is any output yet. - `run` streams the log instead of blocking silently, and refuses to start a task that is already running. - The Automation tab marks a running task, disables its Run now button, and polls while anything is in flight — including the second or two between firing a run and the runner registering it, which is the exact window that used to read as dead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ SCHEDULER_DIR="${HOME}/.claude/scheduler"
|
||||
TASKS_DIR="${SCHEDULER_DIR}/tasks"
|
||||
LOGS_DIR="${SCHEDULER_DIR}/logs"
|
||||
NOTIFICATIONS_DIR="${SCHEDULER_DIR}/notifications"
|
||||
RUNNING_DIR="${SCHEDULER_DIR}/running"
|
||||
ENV_FILE="${SCHEDULER_DIR}/.env"
|
||||
|
||||
TASK_ID="${1:-}"
|
||||
@@ -77,6 +78,27 @@ mkdir -p "$TASK_LOG_DIR"
|
||||
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
|
||||
LOG_FILE="${TASK_LOG_DIR}/${TIMESTAMP}.log"
|
||||
|
||||
# ── Publish run state ───────────────────────────────────────────────────────
|
||||
# A scheduled run is detached — cron has no terminal, and the app fires it as a
|
||||
# detached exec — so without this there is no way to tell a task that is still
|
||||
# thinking from one that died, and a long run reads as a stall. `list`, `status`
|
||||
# and the app's Automation tab all read this file.
|
||||
#
|
||||
# flock above is what actually prevents overlapping runs; this is purely an
|
||||
# observability record, which is why readers verify the pid rather than trust
|
||||
# the file. The EXIT trap covers the crash paths (OOM, container stop, SIGTERM)
|
||||
# that would otherwise leave a task looking like it had been running for days.
|
||||
mkdir -p "$RUNNING_DIR"
|
||||
RUN_STATE="${RUNNING_DIR}/${TASK_ID}.json"
|
||||
trap 'rm -f "$RUN_STATE"' EXIT
|
||||
jq -n \
|
||||
--arg pid "$$" \
|
||||
--arg started "$(date +%s)" \
|
||||
--arg log "$LOG_FILE" \
|
||||
--arg name "$TASK_NAME" \
|
||||
'{pid: ($pid | tonumber), started_epoch: ($started | tonumber), log: $log, name: $name}' \
|
||||
> "$RUN_STATE"
|
||||
|
||||
# ── Execute Claude agent ────────────────────────────────────────────────────
|
||||
{
|
||||
echo "=== Task: $TASK_NAME ($TASK_ID) ==="
|
||||
|
||||
Reference in New Issue
Block a user