Course outline

GitHub Actions / Identity, coordination, and governance / Lesson 17

Diagnostics, timeouts, and safe retry decisions

Locate the first failed boundary and retain evidence without leaking environment data.

About 4 min readContent reviewed
On this page

Lesson goals

  • Distinguish queue, setup, execution, reporting, and target-side failures.
  • Calculate bounded retry time and preserve original outcomes.

Find the first unmet contract

A workflow can fail before a script begins, during setup, in an assertion, while transferring an artifact, or after an external target already accepted work. Parcelโ€™s diagnosis should preserve run identity, attempt, revision, job, step, and first relevant message. Later errors may be consequences: a report cannot upload because no test result was produced, or a cleanup command fails after the original exception. Start with the earliest meaningful boundary rather than the last red line. Keep unknown states explicit when logs are incomplete.

Collect narrow evidence before increasing verbosity

Normal logs, job conclusions, step timing, runner metadata, and selected tool versions often identify the problem. GitHub supports additional runner and step diagnostic logging through documented controls, but enabling it is a repository operation requiring appropriate authority. This course does not enable those controls. More logging can expose sensitive paths, arguments, or transformed secrets and create expensive noise. Collect only what the hypothesis needs, redact before sharing, and retain original failure status separately from the success or failure of the diagnostic export.

Budget the phase that can actually hang

A job timeout bounds runner execution under platform rules; it does not solve missing triggers or guarantee cancellation of external work. Platform limits also constrain run lifetime, waiting, matrices, storage, and concurrency, and those limits can change. Consult the current limits for the actual plan and runner type rather than copying numerical ceilings into application logic. Give long operations their own bounded behavior and leave room for evidence publication. A canceled job with unknown target completion needs observation before repetition.

yaml A timeout and diagnostic-condition fragment
timeout-minutes: 8
steps:
  - name: Run fixture check
    run: python check_fixture.py
  - name: Retain failure context
    if: ${{ failure() }}
    run: printf "%s\n" "fixture check failed; preserve bounded diagnostics"

The script is an assumed fixture dependency and is not supplied by this fragment. The final step prints context only; it is not artifact retention. No job is run, no timeout is measured, and failure() does not mean every canceled state will execute this step.

Retry a known safe unit

Transient acquisition errors can justify a bounded retry when the operation is safe to repeat. A deterministic assertion, missing file, or invalid YAML usually requires a correction. Preserve all attempts instead of reporting only the eventual pass. The complete local model calculates a declared worst-case attempt budget without sleeping. Queue time, runner startup, and cancellation latency are excluded, so it is not an operational guarantee. Retrying an entire job can repeat already completed side effects; identify the smallest incomplete unit first.

python Calculate a synthetic retry budget
attempt_limit = 3
per_attempt_seconds = 15
waits = [2, 5]
assert len(waits) == attempt_limit - 1
print(attempt_limit * per_attempt_seconds + sum(waits))
print("no waiting or external operation performed")
Expected output
52
no waiting or external operation performed

Three fifteen-second attempts and seven seconds of declared waits total fifty-two seconds in the model. The program performs arithmetic only and neither sleeps nor contacts a service.

Reconcile the result with external state

If submission succeeded but verification timed out, inspect the original target operation through the approved owner path. If only report publication failed, repeat that safe publication rather than adopting the package again. A rerun creates another attempt record and may interact with retention, permissions, or changed mutable dependencies, so compare actual inputs. After correction, verify the original contract on an equivalent revision and retain the explanation. Repeated unexplained green reruns should become a tracked reliability issue, not the teamโ€™s normal diagnostic method.

Common errors and fixes

The last log line is treated as the root cause.

Why it happens
A cleanup or report error obscures the first failing boundary.
How to fix it
Preserve the timeline and inspect the earliest meaningful failure.
Prevent it next time
Separate application, infrastructure, and reporting outcomes.

A longer job timeout is used to fix a job that never starts.

Why it happens
Queueing or trigger failure was mistaken for execution duration.
How to fix it
Inspect creation, dependencies, approvals, runner labels, and capacity.
Prevent it next time
Measure queue and execution separately.

A whole job is rerun after a target-side timeout.

Why it happens
The retry unit includes an operation with uncertain external completion.
How to fix it
Observe the original operation and resume only the safe incomplete phase.
Prevent it next time
Define request identity and repeatability before adding retries.

Check your understanding

1. The test command fails and a later report step also fails. Which result matters first?

Show worked solution

Investigate the test failure as the original contract failure while retaining the independent report-channel defect. Fixing publication improves evidence but does not make the tests pass. Do not overwrite either outcome with a generic infrastructure failure label.

2. Three attempts each allow fifteen seconds and waits total seven seconds. Is fifty-two seconds the complete CI elapsed time?

Show worked solution

No. It is only the declared execution-and-wait model. Queueing, setup, transfer, cleanup, and cancellation delays can add time. State those exclusions and measure actual phases before making a service-level feedback promise.

Key takeaways

  • Diagnose the earliest boundary and preserve attempt history.
  • Timeouts and retries need explicit scope and external-state reasoning.

Official references