Skip to content

Commit d51cc3d

Browse files
authored
lint: cap -j=4 and use --allow-parallel-runners (#5334)
Two changes to the four `golangci-lint run` invocations in `Taskfile.yml`: - Add `-j=4` to cap analyzer concurrency. - Add `--allow-parallel-runners` and drop the per-task `TMPDIR` workaround introduced in #5050. `./task lint`, fresh caches, same `tools/go.mod`: | | Cold wall | Cold CPU (user+sys) | Warm wall | |---|---|---|---| | origin/main | 185s | 2282s | 4.1s | | this PR | 76s | 327s | 4.0s | 2.4× faster cold wall, 7× less CPU. Warm runs are cache-bound and unchanged. ## `-j=4` golangci-lint scales poorly past 4–6 workers (upstream [#5149](golangci/golangci-lint#5149)). With three sub-lints running in parallel under `lint-go`, the default `-j=GOMAXPROCS` puts ~48 nominal workers on 16 cores — most of the 2282s on origin/main is kernel scheduling contention. Capping at 4 lets the three modules cooperate. ## `--allow-parallel-runners` By default golangci-lint takes a system-wide lock and refuses to start if another copy is already running. The per-task `TMPDIR` override existed to give each invocation its own copy of that lock file so it didn't collide; `--allow-parallel-runners` tells golangci-lint not to take the lock in the first place. Same outcome, no `TMPDIR` plumbing. Parallel runs happen when `lint-go` fans out to the three module sub-lints, and when multiple worktrees lint at once. Safe to skip the lock because golangci-lint v2.12.0 added content-addressable cache keys ([PR #6445](golangci/golangci-lint#6445)). Before that, two worktrees produced separate cache entries (keyed by absolute path) — no sharing, but also no contention. Now the entries are shared by content, so concurrent runs read and write the same files; the cache uses OS-level file locks with atomic write semantics to keep that safe. `origin/main` already pins v2.12.2. ## Trade-off Two `task lint` runs in the *same* worktree no longer fail-fast with `"parallel golangci-lint is running"` — they race instead, harmlessly but wastefully (duplicate analysis work). Minor. ## Test plan - [x] `task lint` clean - [x] `task lint-q` clean - [x] Parallel `task lint` across two worktrees both succeed - [ ] CI lint job passes This pull request and its description were written by Isaac.
1 parent e06a29d commit d51cc3d

1 file changed

Lines changed: 15 additions & 28 deletions

File tree

Taskfile.yml

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,22 +84,23 @@ tasks:
8484

8585
# `golangci-lint run` typechecks, so it stops at go.mod boundaries. We have
8686
# one task per Go module; `lint-go` composes them to cover the whole repo.
87-
# Children run in parallel — each uses its own TMPDIR (set inline on the
88-
# golangci-lint command below) to avoid the shared /tmp lock that serializes
89-
# concurrent golangci-lint invocations. This matters in two scenarios:
90-
# 1. siblings of `lint-go` running in parallel on subprojects here, and
91-
# 2. `lint-go` invocations in sibling worktrees running at the same time.
92-
# The TMPDIR must live under the repo but NOT equal {{.ROOT_DIR}} itself
93-
# (the Go toolchain refuses a go.mod inside os.TempDir, which would break
94-
# golangci-lint's typechecker).
87+
#
88+
# Flags on every invocation:
89+
# --allow-parallel-runners — by default golangci-lint takes a system-wide
90+
# lock and refuses to start if another copy is already running. This
91+
# flag opts out so parallel runs (e.g. `lint-go`'s three sub-lints, or
92+
# two worktrees linting at once) don't block each other.
93+
# -j=4 — cap analyzer concurrency; higher values use more CPU without
94+
# reducing wall time on this codebase.
95+
#
96+
# Cross-worktree concurrency relies on content-addressable cache keys added
97+
# in golangci-lint v2.12.0; keep the binary at v2.12.0+ in tools/go.mod.
9598
lint-go:
9699
desc: Lint Go files across all modules (root, tools, codegen)
97100
deps: ['lint-go-root', 'lint-go-tools', 'lint-go-codegen']
98101

99102
lint-go-root:
100103
desc: Lint Go files in the root module
101-
vars:
102-
TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-root'
103104
sources: &ROOT_LINT_SOURCES
104105
- "**/*.go"
105106
- exclude: tools/**
@@ -109,48 +110,36 @@ tasks:
109110
- go.sum
110111
- "{{.EMBED_SOURCES}}"
111112
cmds:
112-
- cmd: mkdir -p "{{.TMPDIR}}"
113-
silent: true
114-
- TMPDIR="{{.TMPDIR}}" {{.GO_TOOL}} golangci-lint run ./...
113+
- "{{.GO_TOOL}} golangci-lint run --allow-parallel-runners -j=4 ./..."
115114

116115
lint-go-tools:
117116
desc: Lint Go files in tools/ module
118117
dir: tools
119-
vars:
120-
TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-tools'
121118
sources:
122119
- "**/*.go"
123120
- '{{.ROOT_DIR}}/.golangci.yaml'
124121
- go.mod
125122
- go.sum
126123
cmds:
127-
- cmd: mkdir -p "{{.TMPDIR}}"
128-
silent: true
129124
# gocritic is disabled because root's ruleguard rules path is cwd-relative
130125
# and cannot be resolved from this nested module.
131-
- TMPDIR="{{.TMPDIR}}" {{.GO_TOOL}} golangci-lint run --disable gocritic ./...
126+
- "{{.GO_TOOL}} golangci-lint run --allow-parallel-runners -j=4 --disable gocritic ./..."
132127

133128
lint-go-codegen:
134129
desc: Lint Go files in bundle/internal/tf/codegen module
135130
dir: bundle/internal/tf/codegen
136-
vars:
137-
TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-codegen'
138131
sources:
139132
- "**/*.go"
140133
- '{{.ROOT_DIR}}/.golangci.yaml'
141134
- go.mod
142135
- go.sum
143136
cmds:
144-
- cmd: mkdir -p "{{.TMPDIR}}"
145-
silent: true
146137
# gocritic is disabled because root's ruleguard rules path is cwd-relative
147138
# and cannot be resolved from this nested module.
148-
- TMPDIR="{{.TMPDIR}}" {{.GO_TOOL}} golangci-lint run --disable gocritic ./...
139+
- "{{.GO_TOOL}} golangci-lint run --allow-parallel-runners -j=4 --disable gocritic ./..."
149140

150141
lint-q-go-root:
151142
desc: Lint changed Go files in root module (diff vs main, with --fix). Does not check tools/ or bundle/internal/tf/codegen — use `lint` for full coverage.
152-
vars:
153-
TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-root'
154143
sources:
155144
- "**/*.go"
156145
- exclude: tools/**
@@ -162,9 +151,7 @@ tasks:
162151
- "{{.EMBED_SOURCES}}"
163152
- "**/testdata/**"
164153
cmds:
165-
- cmd: mkdir -p "{{.TMPDIR}}"
166-
silent: true
167-
- TMPDIR="{{.TMPDIR}}" ./tools/lintdiff.py {{.GO_TOOL}} golangci-lint run --fix
154+
- "./tools/lintdiff.py {{.GO_TOOL}} golangci-lint run --allow-parallel-runners -j=4 --fix"
168155

169156
# --- Formatting ---
170157

0 commit comments

Comments
 (0)