thread-priority 3.1.1

Library for managing threads priority and schedule policies
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
name: Nightly Dependency Update

on:
    schedule:
        # One hour after the regular nightly build so they don't run at once.
        - cron: "0 3 * * *"
    workflow_dispatch:

permissions:
    contents: read

jobs:
    test:
        name: Test (updated deps)
        runs-on: ${{ matrix.os || 'ubuntu-latest' }}

        # Resolve to the absolute latest dependency versions, ignoring the crate's
        # rust-version (MSRV). Edition 2024 uses the MSRV-aware resolver (v3), which
        # otherwise caps `cargo update` at "latest 1.85-compatible" versions and
        # defeats the point of this job (it would never see a newer, breaking dep).
        env:
            CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: allow

        strategy:
            fail-fast: false
            matrix:
                name:
                    - stable
                    - beta
                    - nightly
                    - macOS
                    - Windows

                include:
                    - name: beta
                      toolchain: beta
                    - name: nightly
                      toolchain: nightly
                    - name: macOS
                      os: macOS-latest
                    - name: Windows
                      os: windows-latest

        steps:
            - name: Checkout sources
              uses: actions/checkout@v4

            - name: Install toolchain
              uses: dtolnay/rust-toolchain@master
              with:
                  toolchain: ${{ matrix.toolchain || 'stable' }}

            # No build cache here on purpose: freshness is the whole point, a cached
            # target/ keyed on Cargo.toml could otherwise mask a newly published version.
            - name: Update dependencies to latest
              run: cargo update --verbose

            - name: Build all features
              run: cargo build --all-features

            - name: Test all features (other)
              if: runner.os != 'Linux'
              run: cargo test --all-features -- --skip set_deadline_policy

            - name: Test all features (Linux)
              if: runner.os == 'Linux'
              run: sudo -E /home/runner/.cargo/bin/cargo test --all-features

    report:
        name: Report failure
        needs: test
        if: failure()
        runs-on: ubuntu-latest
        permissions:
            issues: write

        steps:
            - name: Open or update tracking issue
              env:
                  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
              run: |
                  set -euo pipefail
                  label="nightly-deps"

                  # Make sure the label exists (no-op if it already does).
                  gh label create "$label" --color B60205 \
                    --description "Nightly dependency-update build failures" || true

                  body="The nightly job that runs \`cargo update\` and rebuilds against the latest compatible dependency versions has **failed**.

                  This usually means a newly published version of an unbounded dependency (e.g. \`windows\`, \`libc = \">=0.2.123\"\`) no longer compiles or passes the tests. Consider pinning an upper bound until it is resolved.

                  Failed run: $RUN_URL"

                  existing=$(gh issue list --state open --label "$label" --json number --jq '.[0].number // empty')

                  if [ -n "$existing" ]; then
                    # Throttle: only re-ping an already-open issue if it's been quiet for
                    # a week, so a persistent failure doesn't add a comment every night.
                    updated=$(gh issue view "$existing" --json updatedAt --jq '.updatedAt')
                    if [ "$(date -d "$updated" +%s)" -lt "$(date -d '7 days ago' +%s)" ]; then
                      gh issue comment "$existing" --body "Nightly dependency update failed again: $RUN_URL"
                    else
                      echo "Issue #$existing updated $updated (< 7 days ago); skipping comment."
                    fi
                  else
                    gh issue create \
                      --title "Nightly dependency update broke the build" \
                      --label "$label" \
                      --body "$body"
                  fi

    # ---------------------------------------------------------------- #
    # 2. Probe: can we bump *beyond* our declared ranges?
    # ---------------------------------------------------------------- #
    detect:
        name: Detect available upgrades
        runs-on: ubuntu-latest
        outputs:
            bumped: ${{ steps.up.outputs.bumped }}
            fp: ${{ steps.fp.outputs.fp }}
        env:
            CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: allow

        steps:
            - name: Checkout sources
              uses: actions/checkout@v4

            - name: Install toolchain
              uses: dtolnay/rust-toolchain@stable

            - name: Install cargo-edit
              uses: taiki-e/install-action@v2
              with:
                  tool: cargo-edit

            # Bump Cargo.toml to the newest versions, crossing SemVer-incompatible
            # boundaries:
            #   a) `cargo upgrade --incompatible` rewrites simple requirements
            #      (e.g. `rstest = "0.25"` -> `"0.26"`).
            #   b) cargo-edit won't cross a two-sided cap on its own, so for the
            #      `windows` range (`>=L, <CAP`) we find the newest stable version
            #      straight from the crates.io sparse index — `windows` is a
            #      `cfg(windows)` dep that `cargo upgrade`/`cargo outdated` can't
            #      see when resolving on Linux — and, if it sits at/above the cap,
            #      raise the cap to the next breaking boundary via
            #      `cargo upgrade --pinned`, keeping the `>=L, <CAP` shape. The
            #      bump is SemVer-aware: a 0.x release bumps the minor, >=1.0 the
            #      major.
            - name: Upgrade requirements to latest (incompatible allowed)
              id: up
              shell: bash
              run: |
                  set -euo pipefail
                  cargo upgrade --incompatible

                  # Newest *stable* (non-prerelease, non-yanked) windows release.
                  # The sparse index lists versions in publish order, so sort by
                  # SemVer rather than trusting the last line — a backport to an
                  # older line can be published after a newer one.
                  latest=$(curl -sSfL https://index.crates.io/wi/nd/windows \
                    | jq -r 'select(.yanked | not) | .vers | select(contains("-") | not)' \
                    | sort -V | tail -1)
                  if [ -z "$latest" ]; then
                    echo "::error::could not determine the latest windows version from crates.io" >&2
                    exit 1
                  fi

                  # Parse the two-sided `>=lower, <cap` windows requirement.
                  lower=$(sed -nE 's/.*version = ">=([0-9.]+), *<[0-9.]+".*/\1/p' Cargo.toml)
                  cap=$(sed -nE 's/.*version = ">=[0-9.]+, *<([0-9.]+)".*/\1/p' Cargo.toml)
                  if [ -z "$lower" ] || [ -z "$cap" ]; then
                    echo "::error::could not parse a '>=L, <C' windows requirement from Cargo.toml" >&2
                    exit 1
                  fi

                  # SemVer-aware compare + next-breaking boundary (0.x bumps the
                  # minor, >=1.0 bumps the major).
                  major_of() { echo "${1%%.*}"; }
                  minor_of() { case "$1" in *.*) local r=${1#*.}; echo "${r%%.*}";; *) echo 0;; esac; }
                  lat_major=$(major_of "$latest"); lat_minor=$(minor_of "$latest")
                  cap_major=$(major_of "$cap");    cap_minor=$(minor_of "$cap")
                  if [ "$lat_major" -gt "$cap_major" ] \
                     || { [ "$lat_major" -eq "$cap_major" ] && [ "$lat_minor" -ge "$cap_minor" ]; }; then
                    if [ "$lat_major" -gt 0 ]; then
                      newcap="$((lat_major + 1)).0"
                    else
                      newcap="0.$((lat_minor + 1))"
                    fi
                    echo "windows: latest $latest >= cap <$cap; raising cap to <$newcap"
                    cargo upgrade -p "windows@>=$lower, <$newcap" --pinned
                  else
                    echo "windows: latest $latest already within <$cap; no change"
                  fi

                  if git diff --quiet -- Cargo.toml; then
                    echo "No upgrades available."
                    echo "bumped=false" >> "$GITHUB_OUTPUT"
                  else
                    echo "Upgrades found:"
                    git --no-pager diff -- Cargo.toml
                    echo "bumped=true" >> "$GITHUB_OUTPUT"
                  fi

            # Content fingerprint of the *proposed* dependency requirements (name +
            # requirement, per kind/target), so open-pr can tell whether this exact
            # bump was already proposed and rejected. cargo parses the manifest, so we
            # don't hand-parse TOML; it's dep-only, so unrelated Cargo.toml edits (e.g.
            # the package version) don't change it.
            - name: Fingerprint the bump
              id: fp
              if: steps.up.outputs.bumped == 'true'
              shell: bash
              run: |
                  set -euo pipefail
                  fp=$(cargo metadata --no-deps --format-version 1 \
                    | jq -r '.packages[0].dependencies
                              | map("\(.target // "any")|\(.kind // "normal")|\(.name)=\(.req)")
                              | sort | join(";")' \
                    | sha256sum | cut -c1-12)
                  echo "Bump fingerprint: $fp"
                  echo "fp=$fp" >> "$GITHUB_OUTPUT"

            - name: Upload bumped manifest
              if: steps.up.outputs.bumped == 'true'
              uses: actions/upload-artifact@v4
              with:
                  name: bumped-manifest
                  path: Cargo.toml

    # If the probe itself errors out (crates.io lookup, manifest parse, ...) it
    # never sets `bumped`, so verify/open-pr/open-issue all skip and nothing is
    # reported. This job surfaces that infrastructure failure.
    probe-broken:
        name: Report broken probe
        needs: detect
        if: failure()
        runs-on: ubuntu-latest
        permissions:
            issues: write

        steps:
            - name: Open or update issue
              env:
                  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
              run: |
                  set -euo pipefail
                  label="nightly-deps-probe"
                  gh label create "$label" --color FBCA04 \
                    --description "Dependency upgrade probe failures" || true

                  body="The nightly dependency **probe** (\`detect\` job) failed before it could determine whether an upgrade is available — e.g. the crates.io index lookup or the \`Cargo.toml\` parse errored. This is a probe-infrastructure failure, not a dependency build failure.

                  Run: $RUN_URL"

                  existing=$(gh issue list --state open --label "$label" --json number --jq '.[0].number // empty')

                  if [ -n "$existing" ]; then
                    # Throttle: only re-ping an already-open issue if it's been quiet for
                    # a week, so a persistent failure doesn't add a comment every night.
                    updated=$(gh issue view "$existing" --json updatedAt --jq '.updatedAt')
                    if [ "$(date -d "$updated" +%s)" -lt "$(date -d '7 days ago' +%s)" ]; then
                      gh issue comment "$existing" --body "Probe (\`detect\`) failed again: $RUN_URL"
                    else
                      echo "Issue #$existing updated $updated (< 7 days ago); skipping comment."
                    fi
                  else
                    gh issue create \
                      --title "Nightly dependency probe (detect) failed" \
                      --label "$label" \
                      --body "$body"
                  fi

    verify:
        name: Verify upgrade
        needs: detect
        if: needs.detect.outputs.bumped == 'true'
        runs-on: ${{ matrix.os || 'ubuntu-latest' }}
        env:
            CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: allow

        strategy:
            fail-fast: false
            matrix:
                name:
                    - Linux
                    - macOS
                    - Windows
                include:
                    - name: macOS
                      os: macOS-latest
                    - name: Windows
                      os: windows-latest

        steps:
            - name: Checkout sources
              uses: actions/checkout@v4

            - name: Apply bumped manifest
              uses: actions/download-artifact@v4
              with:
                  name: bumped-manifest

            - name: Install toolchain
              uses: dtolnay/rust-toolchain@stable

            # Build + test the upgraded manifest, teeing everything to a log so a
            # failure can be attached to the issue verbatim.
            - name: Build & test against upgraded deps
              shell: bash
              run: |
                  set -euo pipefail
                  log="build-${{ runner.os }}.log"
                  run () { echo "+ $*" | tee -a "$log"; "$@" 2>&1 | tee -a "$log"; }
                  run cargo update --verbose
                  run cargo build --all-features
                  if [ "${{ runner.os }}" = "Linux" ]; then
                    run sudo -E /home/runner/.cargo/bin/cargo test --all-features
                  else
                    run cargo test --all-features -- --skip set_deadline_policy
                  fi

            - name: Upload build log
              if: always()
              uses: actions/upload-artifact@v4
              with:
                  name: build-log-${{ runner.os }}
                  path: build-${{ runner.os }}.log
                  if-no-files-found: ignore

    # The verify job above tests on *stable* with the MSRV-aware resolver disabled
    # (`CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: allow`), so it never exercises the
    # crate's declared `rust-version`. A bump that raises a lower bound onto a release
    # that needs a newer Rust would pass verify yet break 1.85 users (and our own MSRV
    # CI). This job re-validates the bumped manifest on the declared MSRV before we
    # open a PR — deliberately *without* the `allow` env so the v3 resolver is in force,
    # mirroring the `cargo check` MSRV gate in ci.yml.
    msrv:
        name: Validate MSRV
        needs: detect
        if: needs.detect.outputs.bumped == 'true'
        runs-on: ubuntu-latest

        steps:
            - name: Checkout sources
              uses: actions/checkout@v4

            - name: Apply bumped manifest
              uses: actions/download-artifact@v4
              with:
                  name: bumped-manifest

            - name: Install toolchain (1.85)
              uses: dtolnay/rust-toolchain@1.85

            - name: Check against MSRV
              shell: bash
              run: |
                  set -euo pipefail
                  log="build-MSRV.log"
                  run () { echo "+ $*" | tee -a "$log"; "$@" 2>&1 | tee -a "$log"; }
                  run cargo check --all-features

            - name: Upload build log
              if: always()
              uses: actions/upload-artifact@v4
              with:
                  name: build-log-MSRV
                  path: build-MSRV.log
                  if-no-files-found: ignore

    open-pr:
        name: Open bump PR
        needs: [detect, verify, msrv]
        if: needs.detect.outputs.bumped == 'true' && needs.verify.result == 'success' && needs.msrv.result == 'success'
        runs-on: ubuntu-latest
        permissions:
            contents: write
            pull-requests: write

        steps:
            - name: Checkout sources
              uses: actions/checkout@v4

            - name: Apply bumped manifest
              uses: actions/download-artifact@v4
              with:
                  name: bumped-manifest

            # Don't re-propose a bump the maintainer already rejected. We keep a single
            # rolling branch (so the open PR is updated in place rather than piling up),
            # and match on the *content fingerprint* stamped into each PR body: skip only
            # if a closed, unmerged PR proposed this exact set of requirement changes. A
            # genuinely different future bump has a different fingerprint and still opens.
            # Matching on the PR record (not the branch) means it works even if the
            # branch was deleted on close.
            - name: Check whether this exact bump was already rejected
              id: rejected
              env:
                  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  FP: ${{ needs.detect.outputs.fp }}
              run: |
                  set -euo pipefail
                  count=$(gh pr list --state all --head nightly/dependency-bump --limit 200 --json state,body \
                    --jq "[.[] | select(.state == \"CLOSED\") | select((.body // \"\") | contains(\"bump-fingerprint: $FP\"))] | length")
                  if [ "${count:-0}" -gt 0 ]; then
                    echo "This exact bump (fingerprint $FP) was already closed unmerged; not re-proposing."
                    echo "skip=true" >> "$GITHUB_OUTPUT"
                  else
                    echo "skip=false" >> "$GITHUB_OUTPUT"
                  fi

            - name: Create or update pull request
              if: steps.rejected.outputs.skip != 'true'
              uses: peter-evans/create-pull-request@v7
              with:
                  branch: nightly/dependency-bump
                  delete-branch: true
                  commit-message: "Bump dependencies to latest"
                  title: "⬆️ Bump dependencies to latest (verified by nightly probe)"
                  labels: nightly-deps-probe
                  body: |
                      The nightly probe upgraded the dependency requirements to their
                      latest versions — including SemVer-incompatible bumps and raising the
                      capped `windows` range — and the full build + test suite passed on
                      Linux, macOS and Windows, plus a `cargo check` on the declared MSRV
                      (1.85).

                      This PR contains the resulting `Cargo.toml` change; review the diff and
                      merge if you're happy to raise the requirements.

                      > Note: opened with the default `GITHUB_TOKEN`, so CI does not re-run on
                      > this PR. The probe already built and tested this exact change — see the
                      > run below.

                      Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

                      <!-- bump-fingerprint: ${{ needs.detect.outputs.fp }} -->

    open-issue:
        name: Report failed upgrade
        needs: [detect, verify, msrv]
        if: needs.detect.outputs.bumped == 'true' && (needs.verify.result == 'failure' || needs.msrv.result == 'failure')
        runs-on: ubuntu-latest
        permissions:
            issues: write

        steps:
            - name: Download build logs
              uses: actions/download-artifact@v4
              with:
                  pattern: build-log-*
                  path: logs

            - name: Open or update issue with error log
              env:
                  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
              run: |
                  set -euo pipefail
                  label="nightly-deps-probe"
                  gh label create "$label" --color FBCA04 \
                    --description "Dependency upgrade probe failures" || true

                  # nullglob so a setup failure that produced no log artifact (every
                  # job dying before `Build & test`) yields an empty array and the
                  # fallback message below, rather than a literal-glob `tail` that
                  # would crash this reporting step under `set -e`.
                  shopt -s nullglob
                  logs=(logs/*/*.log)

                  {
                    echo "The nightly probe upgraded dependencies to their latest versions"
                    echo "(SemVer-incompatible bumps plus raising the capped \`windows\` range)"
                    echo "but the build/test suite or the MSRV check **failed** — so we cannot"
                    echo "raise the requirements yet."
                    echo
                    if [ ${#logs[@]} -eq 0 ]; then
                      echo "_No build logs were produced: the verify/MSRV jobs likely failed during"
                      echo "setup (checkout, artifact download, or toolchain install). See the run._"
                      echo
                    else
                      echo "Tail of each job's log:"
                      echo
                      for f in "${logs[@]}"; do
                        echo "<details><summary>$(basename "$f")</summary>"
                        echo
                        echo '```'
                        tail -n 120 "$f"
                        echo '```'
                        echo
                        echo "</details>"
                        echo
                      done
                    fi
                    echo "Full run: $RUN_URL"
                  } > issue-body.md

                  existing=$(gh issue list --state open --label "$label" --json number --jq '.[0].number // empty')

                  if [ -n "$existing" ]; then
                    # Throttle: only re-ping an already-open issue if it's been quiet for
                    # a week, so a persistent failure doesn't add a comment every night.
                    updated=$(gh issue view "$existing" --json updatedAt --jq '.updatedAt')
                    if [ "$(date -d "$updated" +%s)" -lt "$(date -d '7 days ago' +%s)" ]; then
                      gh issue comment "$existing" --body-file issue-body.md
                    else
                      echo "Issue #$existing updated $updated (< 7 days ago); skipping comment."
                    fi
                  else
                    gh issue create \
                      --title "Dependency upgrade probe failed" \
                      --label "$label" \
                      --body-file issue-body.md
                  fi