Skip to content

Document the component package for users and maintainers#68

Merged
danielorbach merged 10 commits into
mainfrom
issue-10-synctest-docs
Jun 3, 2026
Merged

Document the component package for users and maintainers#68
danielorbach merged 10 commits into
mainfrom
issue-10-synctest-docs

Conversation

@danielorbach
Copy link
Copy Markdown
Owner

@danielorbach danielorbach commented Jun 2, 2026

Issue #10 migrated the lifecycle suite to testing/synctest (#65, #67) and met every acceptance criterion but one: documenting the testing approach. The migrated suite, with the explanatory comments left at its trickier call sites, already demonstrates those patterns, so this change resists manufacturing a large documentation artifact to satisfy the checkbox and instead adds only what earns its place independently.

The component package shipped without any overview, so its pkg.go.dev page showed no description at all; doc.go now supplies a short one and points readers at lifecycle_test.go for the synctest tests that exercise its concurrency. A runnable graceful-shutdown example gives the package its first godoc example, showing the Continue/Stopping idiom a component uses to stop cleanly on request. A short note in the README orients contributors to the synctest harness behind the suite.

There are no production code changes. The documentation deliberately does not restate the testing/synctest contract, which the standard library owns and would only drift from if copied here, and it adds no separate synctest "patterns guide" because the suite itself is that guide. The example demonstrates usage rather than the test harness because a synctest-driven godoc example is impossible: synctest.Test requires a *testing.T that example functions never receive.

@danielorbach danielorbach self-assigned this Jun 2, 2026
@danielorbach
Copy link
Copy Markdown
Owner Author

danielorbach commented Jun 3, 2026

Extended the package overview (doc.go) and documented the loader subpackage so the two read as one story.

  • Testing with synctest — its own overview section (ahead of the usage sections) noting that the lifecycle's concurrency is exercised under testing/synctest, with lifecycle_test.go as the worked examples to follow.
  • Configuring a lifecycle — the Option values that shape a lifecycle (WithName, WithContext, WithLogger, WithStopper), and how the stop request they carry is what L.Continue/L.Stopping report to the running code.
  • Running a program — that a standalone program reaches for the loader subpackage's Entrypoint, which installs a context, a logger, and a SIGINT/SIGTERM handler so an OS signal becomes that same stop request. The subpackage is linked via an import-path doc link (a relative target; component cannot import loader without a cycle, and a relative link definition does not render).
  • loader package — gained its own overview (around Footprint, Load, and Entrypoint), and Entrypoint/EntrypointProc are now documented.

Here is the current pkgsite render, with the in-package symbols resolving to links:

Rendered component package documentation on pkgsite

The package shipped without an overview, so pkg.go.dev showed no
description at all. This adds a short one: what the package provides, how a
lifecycle runs, and where to look (lifecycle_test.go) for the synctest tests
that exercise its concurrency.
A newcomer needs a concrete reference for the shape of a component that
stops on request: the work loop selecting between its own progress and
L.Stopping, and the stopper channel that a program wires to an interrupt
signal.

The example prints fixed start and stop lines rather than a count of work
iterations that depends on timing, so its output is deterministic and the
test runner executes and verifies it in a few milliseconds.
The lifecycle suite depends on testing/synctest for deterministic
concurrency tests. This points contributors at that harness and at
lifecycle_test.go as the pattern to follow when adding such tests.
The example selected over a 1ms work timer and L.Stopping, printing its
shutdown line only on the Stopping branch. When both branches were ready at
once - the normal state on a contended runner whose coarse timer had already
expired by the time the goroutine was scheduled - select chooses a branch
uniformly, so the shutdown line was dropped about half the time and the
verified output failed. CI hit this on the oldstable runner; a forced-
coincidence harness reproduced the skip at ~51%.

The loop now has a single exit: it runs until l.Continue() reports the stop
request, and the shutdown line prints once after the loop. With no select and
no work timer there is no second branch to race, so the output is identical on
every run. The loop body, left as a comment, is where a real component does
its work.
Each method now carries its own runnable example, so it renders on that
method's entry on pkg.go.dev: ExampleL_Continue under Continue and
ExampleL_Stopping under Stopping. The two cover the distinct ways a procedure
observes a stop request: a work loop that checks Continue between units, and a
procedure with nothing to poll that blocks on the Stopping channel.

This replaces the single package-level graceful-shutdown example, which showed
only the loop. Both keep the single linear exit that makes their output
deterministic, and the example comments describe the scenario rather than
opening with the function name.
Point new readers from the package overview to the Option values that
configure a lifecycle (WithName, WithContext, WithLogger, WithStopper) and
to the loader subpackage's Entrypoint, which turns an OS interrupt into the
stop request the running procedure observes.
The component package's overview now points readers here for running a
program, so give loader an overview of its own around Footprint, Load,
and Entrypoint, and document the entry-point functions that hand the
main goroutine to a lifecycle.
The overview already mentions Entrypoint by name; turn the loader
reference into a documentation link so readers can reach the subpackage
directly. The link uses the full import path because component cannot
import loader without creating an import cycle, and a relative link in a
doc comment does not render.
The testing guidance previously trailed the program section as a single
sentence. Give it a named section near the top of the overview so the
synctest harness is visible to maintainers before the usage sections,
and expand it to say what synctest buys a lifecycle test.
Use a repository-relative target so the link resolves to the file on
both GitHub and pkgsite without pinning a host or a branch.
@danielorbach danielorbach force-pushed the issue-10-synctest-docs branch from 6428891 to 3ddcec3 Compare June 3, 2026 13:49
Copy link
Copy Markdown
Collaborator

@galactic-king galactic-king left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielorbach danielorbach merged commit 138c071 into main Jun 3, 2026
7 checks passed
@danielorbach danielorbach deleted the issue-10-synctest-docs branch June 3, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants