You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 2ce6916
Browse filesBrowse the repository at this point in the historyBrowse files
feat: GitHub Action for the baseline check, and run --markdown
action.yml runs traceperf run with --baseline, fails the job on more
calls per request, writes the job summary and keeps one PR comment up
to date. CI runs the action on the batched app (must pass) and its N+1
version (must be caught).
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
-`traceperf/auto` wrote each request tree with its own `appendFileSync`, and under load that showed up as the app's "CPU cost" (`writeFileUtf8`). Writes are batched every 20 ms.
14
14
15
15
### Added
16
+
-**GitHub Action** (`uses: thelastbackspace/traceperf@<tag>`): runs the baseline check, fails the job on more calls per request, and posts one pull-request comment it updates on every push. `traceperf run --markdown file.md` writes the same summary.
16
17
-`traceperf run` reads `traceperf.config.json` (or `--config file`); command-line options win. A `login` step logs in before the traffic and sends the returned token or cookies with every request; `${NAME}` in the file is read from the environment.
17
18
-`npm run eval` scores `traceperf run` on 20 apps in `examples/slow-apps`: 12 with a planted problem, 8 clean ones where the right answer is "no issues". CI fails on any missed problem or false alarm. Before these fixes: 17/17 found, 15 false alarms; after: 17/17, 0.
Or use the action, which also comments on the pull request with what changed, and updates that one comment on every push:
153
+
154
+
<!-- docs:skip -->
155
+
```yaml
156
+
permissions:
157
+
pull-requests: write
158
+
steps:
159
+
- uses: actions/checkout@v4
160
+
- run: npm ci && npm run build && npm run db:seed
161
+
- uses: thelastbackspace/traceperf@v1.9.0
162
+
with:
163
+
run: dist/server.js --path /orders --path /users/1 # or leave out and use traceperf.config.json
164
+
baseline: perf-baseline.json
165
+
```
166
+
167
+
> ### traceperf: ✖ more calls per request than the baseline
168
+
> - ✖ GET /orders: SELECT * FROM items WHERE order_id = ? 0 → 12 per request (an N+1?)
169
+
> - ✖ new problem: N+1 in GET /orders
170
+
171
+
Inputs: `run`, `baseline`, `comment` (default `true`), `fail` (default `true`), `version` (traceperf version, default `1`). Output: `regressed`. The same report goes to the job summary; `--markdown file.md` writes it without the action.
172
+
152
173
`examples/slow-apps/` has 20 small apps: 12 with one planted problem each (blocking in your code and in built-ins, sequential awaits, N+1 over SQL and over HTTP, a slow or flaky dependency, failing requests…) and 8 clean ones where the right answer is "no issues". `npm run eval` scores `run` on them, and CI fails on a missed problem or a false alarm.
153
174
154
175
The same naming works without `run`: `TRACEPERF_PROFILE_BLOCKING=1 node --require traceperf/auto server.js`adds the function names to the exit summary (sampling costs a few percent CPU, so use it while investigating). In code: `profileSlowCalls({ select: root => blockingRanges(root), mergeInlined: true, onProfile })`, then `explain(roots, { hotspots })`.
description: Fail a pull request that adds database queries or HTTP calls per request (an N+1), and comment what changed
3
+
branding:
4
+
icon: activity
5
+
color: orange
6
+
inputs:
7
+
run:
8
+
description: 'Arguments for `traceperf run`: the app and its paths, e.g. "dist/server.js --path /orders --path /users/1". Leave empty to use traceperf.config.json.'
9
+
required: false
10
+
default: ''
11
+
baseline:
12
+
description: Committed baseline file (create it with `npx traceperf run ... --save-baseline perf-baseline.json`)
13
+
required: false
14
+
default: perf-baseline.json
15
+
comment:
16
+
description: Post (and update) one comment on the pull request with the result
17
+
required: false
18
+
default: 'true'
19
+
fail:
20
+
description: Fail the job when a route makes more calls per request than the baseline
21
+
required: false
22
+
default: 'true'
23
+
version:
24
+
description: traceperf version to run (npm version or range, or the path of a local build)
25
+
required: false
26
+
default: '1'
27
+
github-token:
28
+
description: Token for the comment (needs pull-requests write permission)
29
+
required: false
30
+
default: ${{ github.token }}
31
+
outputs:
32
+
regressed:
33
+
description: '"true" when a route makes more calls per request than the baseline'
34
+
value: ${{ steps.run.outputs.regressed }}
35
+
runs:
36
+
using: composite
37
+
steps:
38
+
- id: run
39
+
shell: bash
40
+
env:
41
+
TP_ARGS: ${{ inputs.run }}
42
+
TP_BASELINE: ${{ inputs.baseline }}
43
+
TP_VERSION: ${{ inputs.version }}
44
+
run: |
45
+
report="$RUNNER_TEMP/traceperf.md"
46
+
set +e
47
+
# shellcheck disable=SC2086 # the arguments are a word list on purpose
48
+
case "$TP_VERSION" in
49
+
# A local build (this repository's own CI tests the action with it)
50
+
./*|/*) cli=(node "$TP_VERSION/dist/cli.js") ;;
51
+
*) cli=(npx --yes "traceperf@$TP_VERSION") ;;
52
+
esac
53
+
"${cli[@]}" run $TP_ARGS --baseline "$TP_BASELINE" --markdown "$report"
54
+
code=$?
55
+
set -e
56
+
if [ ! -s "$report" ]; then
57
+
printf '### traceperf: the run failed before it produced a report (exit %s)\n\nSee the job log.\n' "$code" > "$report"
58
+
fi
59
+
cat "$report" >> "$GITHUB_STEP_SUMMARY"
60
+
echo "report=$report" >> "$GITHUB_OUTPUT"
61
+
echo "code=$code" >> "$GITHUB_OUTPUT"
62
+
if [ "$code" -ne 0 ]; then echo "regressed=true" >> "$GITHUB_OUTPUT"; else echo "regressed=false" >> "$GITHUB_OUTPUT"; fi
out.push(`### traceperf: ${failed ? '✖ more calls per request than the baseline' : r.baseline ? '✔ no new queries or calls' : `${r.findings.length ? `${r.findings.length} finding${r.findings.length===1 ? '' : 's'}` : 'no issues found'}`}`,'');
if(!regressions.length&&!improvements.length)out.push('- ✔ same calls per request on every route');
912
+
out.push('',`<sub>Compared with \`${r.baselineFile}\`: calls per request from one-at-a-time requests, so the result does not depend on the machine.</sub>`,'');
913
+
}
914
+
if(r.findings.length){
915
+
out.push('<details><summary>Why it was slow (timings from this CI machine)</summary>','');
0 commit comments