Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e16ca8c
Add Elasticsearch 9 compatibility testing
ejsmith Jul 28, 2026
7da5914
Upgrade Elasticsearch stack to 9.4.2
ejsmith Jul 28, 2026
44efc54
Merge branch 'main' into feature/elasticsearch-9-compatibility
ejsmith Jul 28, 2026
aa3c59c
Address Elasticsearch upgrade review feedback
ejsmith Jul 29, 2026
1e1e857
Protect Elasticsearch release image tags
ejsmith Jul 29, 2026
2558a12
Merge remote-tracking branch 'origin/main' into feature/elasticsearch…
ejsmith Jul 29, 2026
d759315
chore: update Elasticsearch stack to 9.4.4
ejsmith Jul 29, 2026
74ab19f
Test Elasticsearch branch images safely
ejsmith Jul 29, 2026
1cfba76
Address Elasticsearch upgrade migration feedback
ejsmith Jul 29, 2026
9a73c3b
Fix Elasticsearch candidate image isolation
ejsmith Jul 29, 2026
1726e1d
Wait for uncached Elasticsearch image builds
ejsmith Jul 29, 2026
9c63bd7
chore: update Elasticsearch stack to 9.5.0
ejsmith Aug 4, 2026
91c3d72
Merge remote-tracking branch 'origin/main' into feature/elasticsearch…
niemyjski Aug 5, 2026
3045b06
Fix dispatched Elasticsearch candidate selection
niemyjski Aug 5, 2026
52cc62c
Build fork Elasticsearch candidates locally
niemyjski Aug 5, 2026
86bad05
Merge remote-tracking branch 'origin/main' into feature/elasticsearch…
niemyjski Aug 8, 2026
135ed0b
Fix Elasticsearch 9 all-in-one package installation
niemyjski Aug 12, 2026
bed125f
Install archive support in Elasticsearch runtime
niemyjski Aug 12, 2026
77769aa
Install gzip for the .NET runtime archive
niemyjski Aug 12, 2026
9c0eaf6
Check out preview heads for E2E tests
niemyjski Aug 12, 2026
c767edc
Merge remote-tracking branch 'origin/main' into HEAD
niemyjski Aug 19, 2026
3039b22
Merge remote-tracking branch 'origin/main' into HEAD
ejsmith Aug 22, 2026
eab2015
Isolate Elasticsearch 9.5 experiment resources
ejsmith Aug 22, 2026
fcaf376
Experiment with lookup joins for stack rollups
ejsmith Aug 22, 2026
b36f897
Make lookup join stack paging mandatory
ejsmith Aug 23, 2026
91fce99
Refactor stack rollups around ES|QL lookup joins
ejsmith Aug 23, 2026
43fdc2c
Bound E2E readiness probes
ejsmith Aug 23, 2026
9aba87c
Reuse Elasticsearch candidates in stacked PRs
ejsmith Aug 23, 2026
dccd38c
Discover the shared Elasticsearch test endpoint
ejsmith Aug 23, 2026
db15e0a
Use lookup joins for event stack filtering
ejsmith Aug 23, 2026
7a26941
Refresh stacked PR checks
ejsmith Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 75 additions & 4 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ jobs:
timeout-minutes: 30
outputs:
version: ${{ steps.version.outputs.version }}
elasticsearch_image_tag: ${{ steps.elasticsearch_image.outputs.tag }}
build_elasticsearch_image: ${{ steps.elasticsearch_image.outputs.build_locally }}
should_publish: ${{ (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'dev-preview')) && secrets.DOCKER_USERNAME != '' && secrets.DOCKER_PASSWORD != '' }}
is_prod_deploy: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name != 'pull_request' }}
is_dev_deploy: ${{ (github.event_name == 'repository_dispatch' && github.event.action == 'preview') || (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'dev-preview')) }}
Expand Down Expand Up @@ -129,16 +131,76 @@ jobs:
echo "version=$version" >> $GITHUB_OUTPUT
echo "### $version" >> $GITHUB_STEP_SUMMARY

- name: Resolve Elasticsearch image
id: elasticsearch_image
env:
PR_HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }}
PREVIEW_BASE_SHA: ${{ github.event.client_payload.base_sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
run: |
version=$(sed -n 's/.*elasticsearch:\([^ ]*\).*/\1/p' build/docker/elasticsearch/9.x/Dockerfile)
tag=$version
image_changed=false
build_locally=false

if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]] &&
! git diff --quiet origin/main...HEAD -- build/docker/elasticsearch/9.x .github/workflows/elasticsearch-docker-9.yml; then
image_changed=true
elif [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" ]] &&
! git diff --quiet "$PUSH_BEFORE_SHA"..HEAD -- build/docker/elasticsearch/9.x .github/workflows/elasticsearch-docker-9.yml; then
image_changed=true
elif [[ "$GITHUB_EVENT_NAME" == "repository_dispatch" ]] &&
! git diff --quiet "${PREVIEW_BASE_SHA:-origin/main}"...HEAD -- build/docker/elasticsearch/9.x .github/workflows/elasticsearch-docker-9.yml; then
image_changed=true
elif [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]] &&
! git diff --quiet origin/main...HEAD -- build/docker/elasticsearch/9.x .github/workflows/elasticsearch-docker-9.yml; then
image_changed=true
fi

if [[ "$image_changed" == "true" ]]; then
image_sha=$(git ls-files -- build/docker/elasticsearch/9.x .github/workflows/elasticsearch-docker-9.yml | sort | xargs sha256sum | sha256sum | cut -d " " -f 1)
tag="$version-sha256-$image_sha"
image="exceptionless/elasticsearch:$tag"

if [[ "$GITHUB_EVENT_NAME" == "pull_request" && "$PR_HEAD_REPOSITORY" != "$GITHUB_REPOSITORY" ]]; then
build_locally=true
else
for attempt in {1..150}; do
if docker manifest inspect "$image" > /dev/null 2>&1; then
break
fi

if [[ "$attempt" -eq 150 ]]; then
echo "::error::Timed out waiting for $image to be published."
exit 1
fi

sleep 10
done
fi
fi

echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "build_locally=$build_locally" >> "$GITHUB_OUTPUT"
echo "### Elasticsearch image: exceptionless/elasticsearch:$tag" >> "$GITHUB_STEP_SUMMARY"

test-api:
needs: version
runs-on: ubuntu-latest
timeout-minutes: 30
env:
Elasticsearch__ImageTag: ${{ needs.version.outputs.elasticsearch_image_tag }}

steps:
- name: Checkout
uses: actions/checkout@v7
with:
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}

- name: Build fork Elasticsearch candidate locally
if: ${{ needs.version.outputs.build_elasticsearch_image == 'true' }}
run: docker build --tag "exceptionless/elasticsearch:${{ needs.version.outputs.elasticsearch_image_tag }}" --file build/docker/elasticsearch/9.x/Dockerfile build/docker/elasticsearch/9.x

- name: Setup .NET Core
uses: actions/setup-dotnet@v6
with:
Expand Down Expand Up @@ -223,12 +285,21 @@ jobs:
run: echo "npm run test:integration"

test-e2e:
needs: version
runs-on: ubuntu-latest
timeout-minutes: 45
env:
Elasticsearch__ImageTag: ${{ needs.version.outputs.elasticsearch_image_tag }}

steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}

- name: Build fork Elasticsearch candidate locally
if: ${{ needs.version.outputs.build_elasticsearch_image == 'true' }}
run: docker build --tag "exceptionless/elasticsearch:${{ needs.version.outputs.elasticsearch_image_tag }}" --file build/docker/elasticsearch/9.x/Dockerfile build/docker/elasticsearch/9.x

- name: Setup .NET Core
uses: actions/setup-dotnet@v6
Expand Down Expand Up @@ -290,8 +361,8 @@ jobs:
- name: Wait for Aspire Resources
run: |
for attempt in {1..60}; do
if curl -fksS https://web-ex.dev.localhost:7131/api/v2/about > /dev/null &&
curl -fksS https://web-ex.dev.localhost:7131/next/login > /dev/null; then
if curl -fksS --connect-timeout 5 --max-time 10 https://web-ex.dev.localhost:7131/api/v2/about > /dev/null &&
curl -fksS --connect-timeout 5 --max-time 10 https://web-ex.dev.localhost:7131/next/login > /dev/null; then
break
fi

Expand All @@ -310,8 +381,8 @@ jobs:

- name: Verify E2E Endpoints
run: |
curl -fksS https://web-ex.dev.localhost:7131/api/v2/about > /dev/null
curl -fksS https://web-ex.dev.localhost:7131/next/login > /dev/null
curl -fksS --connect-timeout 5 --max-time 10 https://web-ex.dev.localhost:7131/api/v2/about > /dev/null
curl -fksS --connect-timeout 5 --max-time 10 https://web-ex.dev.localhost:7131/next/login > /dev/null

- name: Run Playwright E2E Tests
working-directory: src/Exceptionless.Web/ClientApp
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/elasticsearch-docker-8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ jobs:
working-directory: build/docker/elasticsearch/8.x
run: |
VERSION=$(sed -n 's/.*elasticsearch:\([^ ]*\).*/\1/p' Dockerfile)
docker buildx build --platform linux/amd64,linux/arm64 --output "type=image,push=true" --file ./Dockerfile . --tag exceptionless/elasticsearch:$VERSION --tag exceptionless/elasticsearch:latest
docker buildx build --platform linux/amd64,linux/arm64 --output "type=image,push=true" --file ./Dockerfile . --tag exceptionless/elasticsearch:$VERSION
52 changes: 52 additions & 0 deletions .github/workflows/elasticsearch-docker-9.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Elasticsearch 9.x Docker Image CI

on:
push:
paths:
- "build/docker/elasticsearch/9.x/**"
- ".github/workflows/elasticsearch-docker-9.yml"

jobs:
build:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') != true

steps:
- uses: actions/checkout@v7
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.301
- name: Build Reason
env:
GITHUB_EVENT: ${{ toJson(github) }}
run: "echo ref: ${{github.ref}} event: ${{github.event_name}}"
- name: Build Version
run: |
dotnet tool install --global minver-cli --version 7.0.0
version=$(minver --tag-prefix v)
echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV
echo "VERSION=$version" >> $GITHUB_ENV
echo "### Version: $version" >> $GITHUB_STEP_SUMMARY
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Login to DockerHub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
platforms: linux/amd64,linux/arm64
- name: Build custom Elasticsearch 9.x docker image
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
VERSION=$(sed -n 's/.*elasticsearch:\([^ ]*\).*/\1/p' build/docker/elasticsearch/9.x/Dockerfile)
IMAGE_SHA=$(git ls-files -- build/docker/elasticsearch/9.x .github/workflows/elasticsearch-docker-9.yml | sort | xargs sha256sum | sha256sum | cut -d " " -f 1)
TAGS=(--tag "exceptionless/elasticsearch:$VERSION-sha256-$IMAGE_SHA")
if [[ "$GITHUB_REF" == "refs/heads/$DEFAULT_BRANCH" ]]; then
TAGS+=(--tag "exceptionless/elasticsearch:$VERSION" --tag "exceptionless/elasticsearch:latest")
fi
docker buildx build --platform linux/amd64,linux/arm64 --output "type=image,push=true" --file build/docker/elasticsearch/9.x/Dockerfile build/docker/elasticsearch/9.x "${TAGS[@]}"
6 changes: 5 additions & 1 deletion .github/workflows/preview-command.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ jobs:
const headRepository = pullRequest.head.repo.full_name;
const headRef = pullRequest.head.ref;
const headSha = pullRequest.head.sha;
const baseSha = pullRequest.base.sha;
const headLabel = pullRequest.head.label;
const headShortSha = headSha.slice(0, 12);

Expand All @@ -95,6 +96,7 @@ jobs:
core.setOutput("head-ref", headRef);
core.setOutput("head-label", headLabel);
core.setOutput("head-sha", headSha);
core.setOutput("base-sha", baseSha);
core.setOutput("head-short-sha", headShortSha);

const previewLabel = "dev-preview";
Expand Down Expand Up @@ -142,6 +144,7 @@ jobs:
HEAD_REF: ${{ steps.preview.outputs.head-ref }}
HEAD_LABEL: ${{ steps.preview.outputs.head-label }}
HEAD_SHA: ${{ steps.preview.outputs.head-sha }}
BASE_SHA: ${{ steps.preview.outputs.base-sha }}
with:
script: |
await github.rest.repos.createDispatchEvent({
Expand All @@ -152,7 +155,8 @@ jobs:
pr_number: Number(process.env.PR_NUMBER),
head_ref: process.env.HEAD_REF,
head_label: process.env.HEAD_LABEL,
head_sha: process.env.HEAD_SHA
head_sha: process.env.HEAD_SHA,
base_sha: process.env.BASE_SHA
}
});

Expand Down
22 changes: 12 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ENTRYPOINT ["/app/app-docker-entrypoint.sh"]

# completely self-contained

FROM exceptionless/elasticsearch:8.19.15 AS exceptionless
FROM exceptionless/elasticsearch:9.5.0 AS exceptionless

WORKDIR /app
COPY --from=job-publish /app/src/Exceptionless.Job/out ./
Expand All @@ -113,21 +113,23 @@ COPY ./build/supervisord.conf /etc/
USER root

# install dotnet and supervisor
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
supervisor \
RUN microdnf install -y \
wget \
dos2unix \
ca-certificates \
python3-pip \
\
# .NET dependencies
libc6 \
libgcc-s1 \
libicu74 \
libssl3 \
libstdc++6 \
glibc \
gzip \
libgcc \
libicu \
openssl-libs \
libstdc++ \
tar \
tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& pip3 install --no-cache-dir supervisor==4.3.0 \
&& microdnf clean all \
&& dos2unix /app/docker-entrypoint.sh

ENV discovery.type=single-node \
Expand Down
4 changes: 4 additions & 0 deletions build/docker/elasticsearch/9.x/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# https://www.docker.elastic.co/
FROM docker.elastic.co/elasticsearch/elasticsearch:9.5.0

RUN elasticsearch-plugin install -b mapper-size
8 changes: 4 additions & 4 deletions docker/docker-compose.apm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: "2.2"

services:
setup:
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15
image: docker.elastic.co/elasticsearch/elasticsearch:9.5.0
volumes:
- certs:/usr/share/elasticsearch/config/certs
user: "0"
Expand Down Expand Up @@ -53,7 +53,7 @@ services:
depends_on:
setup:
condition: service_healthy
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15
image: docker.elastic.co/elasticsearch/elasticsearch:9.5.0
volumes:
- certs:/usr/share/elasticsearch/config/certs
- esdata:/usr/share/elasticsearch/data
Expand Down Expand Up @@ -98,7 +98,7 @@ services:
depends_on:
elasticsearch:
condition: service_healthy
image: docker.elastic.co/kibana/kibana:8.19.15
image: docker.elastic.co/kibana/kibana:9.5.0
volumes:
- certs:/usr/share/kibana/config/certs
ports:
Expand All @@ -124,7 +124,7 @@ services:
depends_on:
elasticsearch:
condition: service_healthy
image: docker.elastic.co/apm/apm-server:8.19.15
image: docker.elastic.co/apm/apm-server:9.5.0
volumes:
- certs:/usr/share/apm-server/certs
ports:
Expand Down
6 changes: 4 additions & 2 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ services:
- appdata:/app/storage

elasticsearch:
image: exceptionless/elasticsearch:8.19.15
image: exceptionless/elasticsearch:9.5.0
environment:
discovery.type: single-node
xpack.security.enabled: "false"
Expand All @@ -59,6 +59,8 @@ services:
- 9200:9200
- 9300:9300
volumes:
# Complete the Elasticsearch 8.19 upgrade preflight before reusing this volume with Elasticsearch 9.
# See https://exceptionless.com/docs/self-hosting/upgrading-self-hosted-instance
- esdata7:/usr/share/elasticsearch/data
healthcheck:
test:
Expand All @@ -74,7 +76,7 @@ services:
kibana:
depends_on:
- elasticsearch
image: docker.elastic.co/kibana/kibana:8.19.15
image: docker.elastic.co/kibana/kibana:9.5.0
ports:
- 5601:5601

Expand Down
6 changes: 4 additions & 2 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
elasticsearch:
image: exceptionless/elasticsearch:8.19.15
image: exceptionless/elasticsearch:9.5.0
environment:
node.name: elasticsearch
cluster.name: exceptionless
Expand All @@ -11,6 +11,8 @@ services:
ports:
- 9200:9200
volumes:
# Complete the Elasticsearch 8.19 upgrade preflight before reusing this volume with Elasticsearch 9.
# See https://exceptionless.com/docs/self-hosting/upgrading-self-hosted-instance
- esdata:/usr/share/elasticsearch/data
healthcheck:
test:
Expand All @@ -26,7 +28,7 @@ services:
kibana:
depends_on:
- elasticsearch
image: docker.elastic.co/kibana/kibana:8.19.15
image: docker.elastic.co/kibana/kibana:9.5.0
environment:
xpack.security.enabled: "false"
ports:
Expand Down
Loading
Loading