Skip to content

Commit 8e2f967

Browse files
authored
Merge pull request #6809 from JSONbored/feat/self-host-nightly-fleet-matrix-4899
feat(ci): generalize self-host-nightly to a discovered environment fleet
2 parents f8d1628 + f4eae3c commit 8e2f967

2 files changed

Lines changed: 79 additions & 8 deletions

File tree

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
1-
# Manual maintenance hook for an externally reachable self-host stack. This is deliberately not scheduled while
1+
# Manual maintenance hook for externally reachable self-host stacks. This is deliberately not scheduled while
22
# the review stack is running without colocated GitHub Actions runners.
3+
#
4+
# #4899: generalized from a single hardcoded instance to a fleet matrix. Each self-host instance is modeled
5+
# as its own GitHub Environment (Settings -> Environments), carrying that instance's own `SELF_HOST_URL`
6+
# environment variable and `INTERNAL_JOB_TOKEN` environment secret -- this is the supported way to give a
7+
# matrix job a different secret VALUE per entry while every job still reads the same secret NAME
8+
# (`secrets.INTERNAL_JOB_TOKEN`), since workflow expressions cannot index `secrets.*` by a computed key.
9+
#
10+
# Setup for N instances:
11+
# 1. Create one GitHub Environment per instance (any name, e.g. "primary", "edge-nl-01", "customer-acme").
12+
# 2. On each environment, set the `SELF_HOST_URL` variable and the `INTERNAL_JOB_TOKEN` secret for that
13+
# instance.
14+
# 3. Set the repo-level `SELF_HOST_ENVIRONMENTS` variable to a comma-separated list of those environment
15+
# names, e.g. `primary,edge-nl-01`.
16+
# A single-instance setup works exactly the same way -- one environment, one name in the list.
317
name: self-host maintenance
418

519
on:
@@ -13,30 +27,56 @@ concurrency:
1327
cancel-in-progress: false
1428

1529
jobs:
30+
discover:
31+
if: ${{ vars.SELF_HOST_ENVIRONMENTS != '' }}
32+
runs-on: ubuntu-latest
33+
timeout-minutes: 5
34+
outputs:
35+
environments: ${{ steps.list.outputs.environments }}
36+
steps:
37+
- name: Parse SELF_HOST_ENVIRONMENTS into a JSON matrix list
38+
id: list
39+
env:
40+
SELF_HOST_ENVIRONMENTS: ${{ vars.SELF_HOST_ENVIRONMENTS }}
41+
run: |
42+
json=$(printf '%s' "$SELF_HOST_ENVIRONMENTS" | tr ',' '\n' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e '/^$/d' | jq -R . | jq -sc .)
43+
echo "environments=$json" >> "$GITHUB_OUTPUT"
44+
echo "Discovered instances: $json"
45+
1646
maintenance:
17-
if: ${{ vars.SELF_HOST_URL != '' }}
47+
needs: discover
48+
if: ${{ needs.discover.outputs.environments != '' && needs.discover.outputs.environments != '[]' }}
1849
runs-on: ubuntu-latest
1950
timeout-minutes: 30
51+
strategy:
52+
fail-fast: false
53+
matrix:
54+
environment: ${{ fromJson(needs.discover.outputs.environments) }}
55+
environment: ${{ matrix.environment }}
2056
env:
2157
SELF_HOST_URL: ${{ vars.SELF_HOST_URL }}
2258
INTERNAL_JOB_TOKEN: ${{ secrets.INTERNAL_JOB_TOKEN }}
2359
steps:
24-
- name: Self-host health
60+
- name: Self-host health (${{ matrix.environment }})
2561
run: |
62+
if [ -z "$SELF_HOST_URL" ]; then
63+
echo "✗ SELF_HOST_URL not set on the '${{ matrix.environment }}' environment — skipping."
64+
exit 1
65+
fi
2666
if curl -fsS "$SELF_HOST_URL/ready" >/dev/null; then
27-
echo "✓ self-host ready"
67+
echo "✓ self-host ready (${{ matrix.environment }})"
2868
else
29-
echo "✗ self-host not ready"
69+
echo "✗ self-host not ready (${{ matrix.environment }})"
3070
exit 1
3171
fi
3272
33-
- name: Refresh the RAG index (fan out over configured repos)
73+
- name: Refresh the RAG index (fan out over configured repos) (${{ matrix.environment }})
3474
run: |
3575
if [ -z "$INTERNAL_JOB_TOKEN" ]; then
36-
echo "INTERNAL_JOB_TOKEN not set — skipping RAG refresh (set it as a repo secret to enable)."
76+
echo "INTERNAL_JOB_TOKEN not set on the '${{ matrix.environment }}' environment — skipping RAG refresh."
3777
exit 0
3878
fi
3979
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST "$SELF_HOST_URL/v1/internal/jobs/rag-index" \
4080
-H "authorization: Bearer $INTERNAL_JOB_TOKEN" -H "content-type: application/json" -d '{}')
41-
echo "RAG re-index request → HTTP $code"
81+
echo "RAG re-index request (${{ matrix.environment }}) → HTTP $code"
4282
[ "$code" = "202" ] || [ "$code" = "200" ]

apps/loopover-ui/content/docs/self-hosting-operations.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,37 @@ avoids piling duplicate fan-outs). In metrics, break down deferrals by
850850
`job_type=agent-regate-pr` or `agent-regate-sweep` when GitHub
851851
rate-limit pressure spikes.
852852

853+
## Self-host maintenance workflow (GitHub Actions)
854+
855+
[`self-host-nightly.yml`](https://github.com/JSONbored/loopover/blob/main/.github/workflows/self-host-nightly.yml)
856+
is a manual (`workflow_dispatch`) GitHub Actions workflow that checks
857+
`/ready` against your externally reachable self-host instance and,
858+
if `INTERNAL_JOB_TOKEN` is configured, triggers a RAG re-index fan-out. It is
859+
deliberately not scheduled while the review stack runs without colocated
860+
Actions runners — trigger it by hand from the Actions tab, or wire it into
861+
your own external scheduler if you want it automated.
862+
863+
It validates a **fleet** of instances, not just one. Each instance is
864+
modeled as its own [GitHub
865+
Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment)
866+
(repo Settings → Environments), carrying that instance's own
867+
`SELF_HOST_URL` environment variable and `INTERNAL_JOB_TOKEN` environment
868+
secret — this lets every matrix job read the same secret name while each
869+
instance supplies its own value, since workflow expressions cannot index
870+
`secrets.*` by a computed key.
871+
872+
<CodeBlock
873+
lang="text"
874+
code={`1. Create one GitHub Environment per instance (any name — e.g. "primary", "edge-nl-01").
875+
2. On each environment, set the SELF_HOST_URL variable and the INTERNAL_JOB_TOKEN secret for that instance.
876+
3. Set the repo-level SELF_HOST_ENVIRONMENTS variable to a comma-separated list of those environment names,
877+
e.g. \`primary,edge-nl-01\`.`}
878+
/>
879+
880+
A single-instance setup works exactly the same way — one environment, one
881+
name in the list. The workflow no-ops (skips entirely) when
882+
`SELF_HOST_ENVIRONMENTS` is unset.
883+
853884
## Routine checks
854885

855886
- Queue pending count is not growing without processing.

0 commit comments

Comments
 (0)