Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
657a16e
Changelog
pedanticdev Dec 17, 2025
e3e7007
Merge develop
pedanticdev Dec 18, 2025
49aae25
Adds comprehensive observability infrastructure, clustering capabili…
pedanticdev Dec 21, 2025
1b730f3
Enhancements
pedanticdev Dec 23, 2025
06be264
Develop (#9)
pedanticdev Dec 26, 2025
75f03c9
Develop (#11)
pedanticdev Dec 28, 2025
486d478
Develop (#13)
pedanticdev Dec 28, 2025
fcc21ca
Revert HTF simulation strategy (#14)
pedanticdev Dec 29, 2025
8a8eecf
Scenario-Based Memory Pressure Testing
pedanticdev Dec 29, 2025
07264bc
Develop (#17)
pedanticdev Jan 3, 2026
08b1f71
Jfr integration (#18)
pedanticdev Jan 22, 2026
f92158f
Implement dual comparison on the index page.
Jan 22, 2026
d1ca0c9
Introduce full page comparison
Jan 22, 2026
adce973
Add check for cluster
Jan 22, 2026
77e4230
Add needed modules for use of unsafe by aeron
Mar 16, 2026
1f12804
Update presentation for webinar
Mar 17, 2026
47ef99e
Fix notes display
Mar 17, 2026
9f22fd8
Increase method count via ta4J library
Mar 18, 2026
74c9c55
Fix Luqman's bio
Mar 23, 2026
eb1d08a
Update README
Mar 23, 2026
f9854bd
Webinar
May 11, 2026
e550ccc
Make JFR opt-in and harden the recording REST endpoint
May 11, 2026
e91aea2
Add JNation workshop materials
May 11, 2026
7e0db69
Adopt single-Prime workshop compose, ops docs, jfr-query helper
May 11, 2026
3ceaeb6
Add quickstart.sh for one-command workshop bring-up
May 18, 2026
3d7dde4
Final workshop prep: ZGC+G1 dual setup, all docs updated
May 23, 2026
59a7942
Refactor: trading-domain scenarios, runtime-neutral slides + deck
May 25, 2026
f49cf7f
Refactor workshop handbook
May 26, 2026
ba12d51
Update CDN library versions, fix Reveal.js 6 plugin paths
May 26, 2026
cd3d2d3
Fix broken ports, image names, and stale file references in workshop …
May 26, 2026
0196fe4
Fix broken preset URLs, update Hazelcast naming, apply Spotless
May 27, 2026
eb947ad
Improve workshop readability: visual triage flow, severity columns, G…
May 27, 2026
5f33d09
Add repo banner with branch link to workshop page
May 27, 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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# TradeStreamEE Environment Variables

# Payara Micro Version (used by all Dockerfiles)
PAYARA_VERSION=7.2026.5

# JVM Options for Azul Platform Prime
# Adjust these for your performance requirements
JAVA_OPTS=-XX:+UseZGC -Xms512m -Xmx2g -Xlog:gc*:file=/opt/payara/gc.log:time,uptime:filecount=5,filesize=10M -Djava.net.preferIPv4Stack=true
Expand Down
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CI/CD Pipeline

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

jobs:
build-and-test:
name: Build and Test
runs-on: ubuntu-latest

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

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'maven'

- name: Build with Maven
run: ./mvnw clean compile

- name: Generate SBE sources
run: ./mvnw generate-sources

- name: Run tests with JaCoCo
run: ./mvnw clean test jacoco:report -Pcoverage

- name: Check coverage thresholds
run: |
COVERAGE=$(grep -oP '(?<=Total.*?">).*?(?=%</td>)' target/site/jacoco/index.html | head -1)
echo "Coverage: $COVERAGE%"

if (( $(echo "$COVERAGE < 15" | bc -l) )); then
echo "❌ Coverage ($COVERAGE%) is below minimum threshold (15%)"
exit 1
else
echo "✅ Coverage ($COVERAGE%) meets minimum threshold (15%)"
fi
33 changes: 32 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.settings
.project
.classpath
deployment/

*.iml
.DS_Store
Expand All @@ -27,4 +28,34 @@ container/
docs/*
*.md
!README.md
*.pdf
*.pdf
*.jar
monitoring/jmx-exporter/*.jar
monitoring/logs/
monitoring/gc-logs/
monitoring/prometheus/data/
monitoring/grafana/data/
monitoring/loki/data/

# Runtime artefacts produced by start-comparison.sh and the running clusters.
# Bind-mounted JFR dumps land here; the curated workshop set lives in
# workshop/recordings/ instead.
monitoring/recordings/
monitoring/metrics.log
monitoring/.scraper.pid

# Crash dumps from any local JVM (Zing safepoint aborts in particular).
hs_err_pid*.log
hs_err_pid*

# Workshop tree: everything is intentional content. Re-include it explicitly
# so the broad *.md / *.jar ignores above don't swallow it.
!workshop/
!workshop/**
!workshop/**/*.md
!workshop/**/*.jfc
!workshop/**/*.jfr
!workshop/**/*.java
!workshop/**/*.xml
!workshop/**/*.sh
!workshop/**/*.txt
Binary file added .mvn/wrapper/maven-wrapper.jar
Binary file not shown.
18 changes: 18 additions & 0 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
64 changes: 64 additions & 0 deletions .profileconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"jfrConfig": {
"settings": "profile"
},
"asyncProfilerConfig": {
"jfrsync": true,
"alloc": true,
"event": "wall",
"misc": ""
},
"file": "$PROJECT_DIR/profile.jfr",
"conversionConfig": {
"nonProjectPackagePrefixes": [
"java.",
"javax.",
"kotlin.",
"jdk.",
"com.google.",
"org.apache.",
"org.spring.",
"sun.",
"scala."
],
"enableMarkers": true,
"initialVisibleThreads": 10,
"initialSelectedThreads": 10,
"includeGCThreads": false,
"includeInitialSystemProperty": false,
"includeInitialEnvironmentVariables": false,
"includeSystemProcesses": false,
"ignoredEvents": [
"jdk.ActiveSetting",
"jdk.ActiveRecording",
"jdk.BooleanFlag",
"jdk.IntFlag",
"jdk.DoubleFlag",
"jdk.LongFlag",
"jdk.NativeLibrary",
"jdk.StringFlag",
"jdk.UnsignedIntFlag",
"jdk.UnsignedLongFlag",
"jdk.InitialSystemProperty",
"jdk.InitialEnvironmentVariable",
"jdk.SystemProcess",
"jdk.ModuleExport",
"jdk.ModuleRequire"
],
"minRequiredItemsPerThread": 3
},
"additionalGradleTargets": [
{
"targetPrefix": "quarkus",
"optionForVmArgs": "-Djvm.args",
"description": "Example quarkus config, adding profiling arguments via -Djvm.args option to the Gradle task run"
}
],
"additionalMavenTargets": [
{
"targetPrefix": "quarkus:",
"optionForVmArgs": "-Djvm.args",
"description": "Example quarkus config, adding profiling arguments via -Djvm.args option to the Maven goal run"
}
]
}
71 changes: 48 additions & 23 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,58 +1,83 @@
# Multi-stage Dockerfile for TradeStreamEE
# Uses Azul Platform Prime (Zing) for Pauseless Garbage Collection demonstration
# Uses Azul Zulu 25 with ZGC for low-latency concurrent garbage collection

FROM azul/zulu-openjdk:21 AS build
FROM azul/zulu-openjdk:25-latest AS build
WORKDIR /app

# Copy Maven wrapper and pom.xml first for better layer caching
COPY mvnw .
COPY mvnw.cmd .
COPY spotless ./spotless
COPY .mvn .mvn
COPY pom.xml .

RUN ./mvnw dependency:go-offline -B

COPY src ./src

RUN ./mvnw spotless:apply
RUN ./mvnw clean package -DskipTests

# Use Azul Platform Prime for C4 GC
FROM azul/prime:21
# Azul Zulu 25 with ZGC for concurrent garbage collection
FROM azul/zulu-openjdk:25-latest

LABEL maintainer="TradeStreamEE"
LABEL description="High-frequency trading dashboard with Aeron + SBE + Payara Micro + Azul C4"
LABEL description="High-frequency trading dashboard with Aeron + SBE + Payara Micro + Zulu 25 ZGC"

WORKDIR /opt/payara

# Download Payara Micro
ARG PAYARA_VERSION=7.2025.2
RUN apt-get update && \
apt-get install -y wget curl && \
wget -q -O payara-micro.jar \
"https://nexus.payara.fish/repository/payara-community/fish/payara/extras/payara-micro/${PAYARA_VERSION}/payara-micro-${PAYARA_VERSION}.jar" && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Add Payara Micro from URL
ARG PAYARA_VERSION=7.2026.5
ADD https://nexus.payara.fish/repository/payara-community/fish/payara/extras/payara-micro/${PAYARA_VERSION}/payara-micro-${PAYARA_VERSION}.jar /opt/payara/payara-micro.jar

# Copy WAR file from build stage
COPY --from=build /app/target/*.war ROOT.war

# Copy entrypoint script for JFR configuration
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# Create recordings directory for JFR output and gc-logs for GC logs
RUN mkdir -p /opt/payara/recordings /opt/payara/gc-logs && chmod 777 /opt/payara/recordings /opt/payara/gc-logs

EXPOSE 8080
EXPOSE 9009

# Default JVM Options for Azul Platform Prime
# Note: These are defaults - can be overridden via docker-compose or docker run -e
# Azul Platform Prime uses C4 GC by default - no need to specify -XX:+UseZGC
ENV JAVA_OPTS="-Xms2g \
-Xmx4g \
-Xlog:gc*:file=/opt/payara/gc.log:time,uptime:filecount=5,filesize=10M \
-XX:+UnlockDiagnosticVMOptions \
-XX:+UnlockExperimentalVMOptions \
# Default JVM Options for Azul Zulu 25 + ZGC
#
# NOTE: These JAVA_OPTS are used for single-instance deployments (start.sh script).
# For cluster deployments (start-comparison.sh), these values are overridden by
# docker-compose-{c4,g1}.yml environment variables. See those files for actual
# runtime flags in cluster mode.
#
# ZGC is a concurrent collector with sub-millisecond pauses on Java 25.
#
# JFR is OFF by default. Ad-hoc recordings are produced via the /api/jfr REST
# endpoints. To enable an always-on circular recording, set JFR_ALWAYS_ON=true
# in the environment; see docker-entrypoint.sh.
ENV JAVA_OPTS="-Xms8g \
-Xmx8g \
-XX:+UseZGC \
-Xlog:gc*:file=/opt/payara/gc-logs/gc.log:time,uptime,level,tags:filecount=5,filesize=10M \
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED \
--add-opens java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens java.base/java.nio=ALL-UNNAMED \
-XX:+AlwaysPreTouch \
-XX:-UseBiasedLocking \
-Djava.net.preferIPv4Stack=true"
-XX:+UseTransparentHugePages \
-XX:+UseStringDeduplication \
-XX:+OptimizeStringConcat \
-Djava.net.preferIPv4Stack=true \
-Xlog:jfr*=info"

# Set recording name for JFR
ENV RECORDING_NAME="production"

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/trader-stream-ee/api/status || exit 1

# Use entrypoint to handle JFR configuration
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]

# Run Payara Micro with the WAR
CMD java ${JAVA_OPTS} -jar payara-micro.jar --deploy ROOT.war --contextroot trader-stream-ee --nohazelcast
84 changes: 84 additions & 0 deletions Dockerfile.scale
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Multi-stage Dockerfile for TradeStreamEE with Hazelcast Clustering
# Uses Azul Zulu 25 with ZGC for low-latency concurrent garbage collection

FROM azul/zulu-openjdk:25-latest AS build
WORKDIR /app

# Copy Maven wrapper and pom.xml first for better layer caching
COPY mvnw .
COPY mvnw.cmd .
COPY .mvn .mvn
COPY pom.xml .
COPY spotless ./spotless

RUN ./mvnw dependency:go-offline -B

COPY src ./src

RUN ./mvnw spotless:apply
RUN ./mvnw clean package -DskipTests

# Azul Zulu 25 with ZGC for concurrent garbage collection
FROM azul/zulu-openjdk:25-latest

LABEL maintainer="TradeStreamEE"
LABEL description="High-frequency trading dashboard with Aeron + SBE + Payara Micro + Zulu 25 ZGC + Hazelcast Clustering"

WORKDIR /opt/payara

# Add Payara Micro from URL
ARG PAYARA_VERSION=7.2026.5
ADD https://nexus.payara.fish/repository/payara-community/fish/payara/extras/payara-micro/${PAYARA_VERSION}/payara-micro-${PAYARA_VERSION}.jar /opt/payara/payara-micro.jar

# Copy WAR file from build stage
COPY --from=build /app/target/*.war trader-stream-ee.war

# Create recordings directory for JFR output and gc-logs for GC logs
RUN mkdir -p /opt/payara/recordings /opt/payara/gc-logs && chmod 777 /opt/payara/recordings /opt/payara/gc-logs

EXPOSE 8080
EXPOSE 5701

# Default JVM Options for Azul Zulu 25 + ZGC
#
# NOTE: These JAVA_OPTS are defaults for the cluster image. However, when launched
# via docker-compose-c4.yml, these values are overridden by environment variables
# in that file. See docker-compose-c4.yml for actual runtime flags in cluster mode.
#
# Reduced heap size (4GB vs 8GB) for multi-instance deployments.
# ZGC is a concurrent collector with sub-millisecond pauses on Java 25.
#
# JFR is OFF by default. Workshop scenarios use ad-hoc recordings via the REST API
# (POST /api/jfr/recording/start). To enable a long-running always-on circular
# recording, set JFR_ALWAYS_ON=true in the environment.
ENV JAVA_OPTS="-Xms4g \
-Xmx4g \
-XX:+UseZGC \
-Xlog:gc*:file=/opt/payara/gc-logs/gc.log:time,uptime,level,tags:filecount=5,filesize=10M \
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED \
--add-opens java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens java.base/java.nio=ALL-UNNAMED \
-XX:+AlwaysPreTouch \
-XX:+UseTransparentHugePages \
-XX:+UseStringDeduplication \
-XX:+OptimizeStringConcat \
-Djava.net.preferIPv4Stack=true \
-Xlog:jfr*=info"

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD wget --spider -q http://localhost:8080/trader-stream-ee/api/status || exit 1

# Copy Hazelcast configuration
COPY src/main/resources/hazelcast-config.xml /opt/payara/hazelcast-config.xml

# Set unique cluster name for ZGC environment and update discovery members
RUN sed -i 's/payara-trader-cluster/payara-trader-zgc/' /opt/payara/hazelcast-config.xml && \
sed -i 's/trader-stream-/trader-stream-zgc-/' /opt/payara/hazelcast-config.xml

# Run Payara Micro with the WAR.
# NOTE: --nohazelcast is omitted so clustering stays enabled.
# When JFR_ALWAYS_ON=true is set, the shell substitution below appends a
# circular always-on recording. Otherwise only ad-hoc recordings via the
# /api/jfr REST endpoints will produce .jfr files.
CMD ["sh", "-c", "exec java $JAVA_OPTS ${JFR_ALWAYS_ON:+-XX:StartFlightRecording=name=${JFR_RECORDING_NAME:-zgc-cluster},filename=/opt/payara/recordings/recording.jfr,dumponexit=true,maxage=1h,maxsize=1g,method-profiling=normal -XX:FlightRecorderOptions=stackdepth=256} -jar payara-micro.jar --deploy /opt/payara/trader-stream-ee.war --contextroot trader-stream-ee --hzconfigfile /opt/payara/hazelcast-config.xml"]
Loading