hmm

db274ab · gmorell · 2026-05-22 16:37

2 files +37 -6

Files changed

modified lib/git_gud_web/controllers/runner_controller.ex
+17 −2
@@ -215,14 +215,29 @@ defmodule GitGudWeb.RunnerController do
215 215 # ── update_task ──────────────────────────────────────────────────────
216 216
217 217 def update_task(conn, _params) do
218 with {:ok, %UpdateTaskRequest{state: state}} <-
218 + with {:ok, %UpdateTaskRequest{state: state} = req} <-
219 219 decode_request(conn, UpdateTaskRequest),
220 220 %RunnerSchema{} = _runner <- authenticate(conn) do
221 221 job_id = (state && state.id) || 0
222 222
223 + require Logger
224 +
225 + Logger.info(
226 + "update_task incoming state.id=#{inspect(job_id)} " <>
227 + "state.result=#{inspect(state && state.result)} " <>
228 + "outputs=#{inspect(req.outputs |> Map.keys() |> Enum.take(5))}"
229 + )
230 +
223 231 case GitGud.Repo.get(GitGud.Workflows.WorkflowJob, job_id) do
224 232 nil ->
225 error(conn, :not_found, "no such job")
233 + # Ack-and-ignore. Forgejo-runner retries indefinitely on a
234 + # 404, which clobbers logs even when the work is fundamentally
235 + # complete (job long since reaped, db rolled back, etc.).
236 + # We log the miss for forensics but echo back what the runner
237 + # told us so it can stop pestering and free the worker slot.
238 + Logger.warning("update_task lookup miss — acking anyway for state.id=#{inspect(job_id)}")
239 +
240 + respond(conn, %UpdateTaskResponse{state: state, sent_outputs: []})
226 241
227 242 job ->
228 243 mapped = map_result(state && state.result)
modified priv/proto/runner/v1/messages.proto
+20 −4
@@ -12,6 +12,7 @@ syntax = "proto3";
12 12 package runner.v1;
13 13
14 14 import "google/protobuf/timestamp.proto";
15 +import "google/protobuf/struct.proto";
15 16
16 17 // ── Ping ─────────────────────────────────────────────────────────────
17 18
@@ -70,16 +71,31 @@ enum Result {
70 71 RESULT_SKIPPED = 4;
71 72 }
72 73
74 +// Per-need state — the runner needs the parent-job result to drive
75 +// `needs.<id>.result` and the parent's outputs map.
76 +message TaskNeed {
77 + Result result = 1;
78 + map<string, string> outputs = 2;
79 +}
80 +
73 81 message Task {
74 82 int64 id = 1;
75 83 // gzip-compressed YAML of the job definition the runner should execute.
76 84 bytes workflow_payload = 2;
77 // Context the runner injects into `${{ github.* }}` and friends.
78 map<string, string> context = 3;
85 + // Context the runner injects into `${{ github.* }}` etc. Forgejo's
86 + // proto switched this from `map<string,string>` to a Struct so values
87 + // can carry richer types (nested objects, numbers, bools). String
88 + // values are still the common case for us.
89 + google.protobuf.Struct context = 3;
79 90 // Repo / org secrets the job can read via `${{ secrets.* }}`.
80 91 map<string, string> secrets = 4;
81 repeated string needs = 5;
82 map<string, string> vars = 6;
92 + // 5 = `machine` (deprecated upstream, leave unset).
93 + string machine = 5;
94 + // `needs.<job_id>` lookups. Each prior job's result + its declared
95 + // outputs are available; this map is keyed by the upstream job's id.
96 + map<string, TaskNeed> needs = 6;
97 + // Repo / org variables (non-secret); `${{ vars.* }}`.
98 + map<string, string> vars = 7;
83 99 }
84 100
85 101 message FetchTaskRequest {

Parents: 91bcbd0