Skip to content

Development: Check bean instantiations on startup #24

Development: Check bean instantiations on startup

Development: Check bean instantiations on startup #24

name: Check Bean Instantiations on Startup
on:
push:
branches: [ develop ]
paths:
- src/main/java/**
pull_request:
# TODO revert this before merging
# paths:
# - src/main/java/**
jobs:
build:
name: Check Bean Instantiations on Startup
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Build application
run: ./gradlew clean bootJar -x test -x webapp
- name: Start Spring Boot app
run: |
PROFILES=dev,localci,lti,aeolus,theia,iris,localvc,artemis,scheduling,buildagent,core,ldap
JAR=$(ls build/libs/Artemis*.jar | head -n1)
nohup java -jar $JAR \
--spring.profiles.active=$PROFILES \
--artemis.user-management.passkey.enabled=true \
--artemis.user-management.use-external=false \
--artemis.iris.url=http://iris.fake \
--artemis.iris.secret-token=token \
--spring.liquibase.enabled=false \
--spring.datasource.url="jdbc:h2:mem:mydb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" \
--spring.datasource.username=sa \
--spring.datasource.password= \
--eureka.client.enabled=false \
--aeolus.url=http://aeolus.fake \
> app.log 2>&1 &
echo $! > app.pid
- name: Wait for the application to start
run: |
# Configuration variables
RUNNING_MESSAGE="'Artemis is running!'"
STARTUP_TIMEOUT_ATTEMPTS=30
STARTUP_RETRY_INTERVAL=2
STARTUP_TOTAL_TIMEOUT=$((STARTUP_TIMEOUT_ATTEMPTS * STARTUP_RETRY_INTERVAL))
LOG_FILE="app.log"
echo "Waiting up to ${STARTUP_TOTAL_TIMEOUT}s for $RUNNING_MESSAGE to appear in $LOG_FILE..."
isAppRunning=false
for i in $(seq 1 $STARTUP_TIMEOUT_ATTEMPTS); do
if grep -q $RUNNING_MESSAGE $LOG_FILE; then
isAppRunning=true
echo "✅ Found $RUNNING_MESSAGE in $LOG_FILE after $i attempts"
break
fi
echo " attempt $i/$STARTUP_TIMEOUT_ATTEMPTS: not found yet"
sleep $STARTUP_RETRY_INTERVAL
done
if [ "$isAppRunning" = false ]; then
echo "❌ Timeout: $RUNNING_MESSAGE not found in $LOG_FILE"
cat $LOG_FILE
exit 1
fi
- name: Extract and validate startup bean instantiation metrics
run: |
# Configuration variables
STARTUP_LOG_PATTERN="Bean instantiation graph exported to startupBeans\.dot \(([0-9]+) edges, longest dependency chain: \[([^\]]*)\]\)"
MIN_INSTANTIATED_BEANS=20
MAX_INSTANTIATED_BEANS=94
MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH=9
LOG_FILE="app.log"
# Extract search text from pattern (everything before opening parenthesis)
STARTUP_SEARCH=$(echo "$STARTUP_LOG_PATTERN" | sed 's/ \\(.*$//')
LINE=$(grep -E "$STARTUP_SEARCH" $LOG_FILE) \
|| { echo "❌ No startup metrics line found"; cat $LOG_FILE; exit 1; }
if [[ "$LINE" =~ $STARTUP_LOG_PATTERN ]]; then
INSTANTIATED_BEANS=${BASH_REMATCH[1]}
LONGEST_CHAIN_CONTENT=${BASH_REMATCH[2]}
# Count chain length by counting commas and adding 1 (if not empty)
if [ -n "$LONGEST_CHAIN_CONTENT" ]; then
ACTUAL_MAX_CHAIN_LENGTH=$(echo "$LONGEST_CHAIN_CONTENT" | tr ',' '\n' | wc -l)
else
ACTUAL_MAX_CHAIN_LENGTH=0
fi
else
echo "❌ Failed to parse startup metrics from: $LINE"
exit 1
fi
echo "• Number of instantiated beans = $INSTANTIATED_BEANS"
echo "• Longest dependency chain length = $ACTUAL_MAX_CHAIN_LENGTH"
echo "• Longest chain: [$LONGEST_CHAIN_CONTENT]"
echo "Validating against thresholds: MIN_INSTANTIATED_BEANS=$MIN_INSTANTIATED_BEANS (expected ≥ $MIN_INSTANTIATED_BEANS), MAX_INSTANTIATED_BEANS=$MAX_INSTANTIATED_BEANS (expected ≤ $MAX_INSTANTIATED_BEANS), MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH=$MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH (expected ≤ $MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH)"
if (( INSTANTIATED_BEANS < MIN_INSTANTIATED_BEANS )); then
echo "❌ $INSTANTIATED_BEANS < $MIN_INSTANTIATED_BEANS beans. Something seems to be wrong, as usually more beans are instantiated."
exit 1
fi
if (( INSTANTIATED_BEANS > MAX_INSTANTIATED_BEANS )); then
echo "❌ $INSTANTIATED_BEANS > $MAX_INSTANTIATED_BEANS threshold"
exit 1
fi
if (( ACTUAL_MAX_CHAIN_LENGTH > MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH )); then
echo "❌ Longest dependency chain length $ACTUAL_MAX_CHAIN_LENGTH > $MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH threshold"
exit 1
fi
echo "✅ Final values → Beans: $INSTANTIATED_BEANS; Longest dependency chain length: $ACTUAL_MAX_CHAIN_LENGTH"
echo "🎉 Startup bean instantiation metrics within expected ranges"
- name: Check for startup dependency chains exceeding threshold
run: |
# Configuration variables
STARTUP_DEEP_CHAIN_PATTERN="Startup long bean instantiation chain"
MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH=9
LOG_FILE="app.log"
echo "Checking for startup dependency chains exceeding threshold..."
if (( ACTUAL_MAX_CHAIN_LENGTH > MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH )); then
echo "❌ Startup dependency chain length $ACTUAL_MAX_CHAIN_LENGTH > $MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH threshold"
echo "Chains exceeding threshold:"
grep -E "$STARTUP_DEEP_CHAIN_PATTERN" $LOG_FILE || echo " (No detailed chains found in log)"
echo "🔧 These chains violate the threshold MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH. Please refactor them to break these chains."
exit 1
else
echo "✅ No startup dependency chains exceed the threshold of $MAX_STARTUP_DEPENDENCY_CHAIN_LENGTH"
fi
- name: Extract and validate deferred eager bean chain length
run: |
DEFERRED_BEAN_PATTERN="Maximum dependency chain length during deferred eager init: ([0-9]+)"
DEFERRED_TIMEOUT_ATTEMPTS=10
DEFERRED_RETRY_INTERVAL=3
DEFERRED_TOTAL_TIMEOUT=$((DEFERRED_TIMEOUT_ATTEMPTS * DEFERRED_RETRY_INTERVAL))
MIN_DEFERRED_CHAIN_LENGTH=1
MAX_DEFERRED_CHAIN_LENGTH=15
LOG_FILE="app.log"
LOG_TAIL_LINES=50
# Extract search text from pattern (everything before :)
DEFERRED_BEAN_SEARCH=$(echo "$DEFERRED_BEAN_PATTERN" | sed 's/:.*$//')
echo "Waiting for deferred eager bean initialization to complete..."
DEFERRED_LINE=""
for i in $(seq 1 $DEFERRED_TIMEOUT_ATTEMPTS); do
DEFERRED_LINE=$(grep -E "$DEFERRED_BEAN_SEARCH" $LOG_FILE 2>/dev/null || true)
if [ -n "$DEFERRED_LINE" ]; then
echo "✅ Found deferred eager bean initialization log after $i attempts"
break
fi
echo " attempt $i/$DEFERRED_TIMEOUT_ATTEMPTS: deferred eager bean initialization not completed yet"
sleep $DEFERRED_RETRY_INTERVAL
done
if [ -z "$DEFERRED_LINE" ]; then
echo "❌ No deferred eager bean chain length line found after ${DEFERRED_TOTAL_TIMEOUT}s"
echo "Last $LOG_TAIL_LINES lines of $LOG_FILE:"
tail -$LOG_TAIL_LINES $LOG_FILE
exit 1
fi
if [[ "$DEFERRED_LINE" =~ $DEFERRED_BEAN_PATTERN ]]; then
DEFERRED_CHAIN_LENGTH=${BASH_REMATCH[1]}
else
echo "❌ Failed to parse deferred eager bean chain length from: $DEFERRED_LINE"
exit 1
fi
echo "• Maximum dependency chain length during deferred eager bean initialization = $DEFERRED_CHAIN_LENGTH"
echo "Validating against thresholds: MIN_DEFERRED_CHAIN_LENGTH=$MIN_DEFERRED_CHAIN_LENGTH (expected ≥ $MIN_DEFERRED_CHAIN_LENGTH), MAX_DEFERRED_CHAIN_LENGTH=$MAX_DEFERRED_CHAIN_LENGTH (expected ≤ $MAX_DEFERRED_CHAIN_LENGTH)"
if (( DEFERRED_CHAIN_LENGTH < MIN_DEFERRED_CHAIN_LENGTH )); then
echo "❌ Deferred chain length $DEFERRED_CHAIN_LENGTH < $MIN_DEFERRED_CHAIN_LENGTH. Something seems to be wrong, as usually some deferred beans are instantiated."
exit 1
fi
if (( DEFERRED_CHAIN_LENGTH > MAX_DEFERRED_CHAIN_LENGTH )); then
echo "❌ Deferred chain length $DEFERRED_CHAIN_LENGTH > $MAX_DEFERRED_CHAIN_LENGTH threshold"
exit 1
fi
echo "✅ Deferred eager bean chain length: $DEFERRED_CHAIN_LENGTH"
echo "🎉 Deferred eager bean dependency chain length within expected ranges"
- name: Check for deferred dependency chains exceeding threshold
run: |
# Configuration variables
DEFERRED_DEEP_CHAIN_PATTERN="Deferred long bean instantiation chain"
MAX_DEFERRED_DEPENDENCY_CHAIN_LENGTH=15
LOG_FILE="app.log"
echo "Checking for deferred dependency chains exceeding threshold..."
if (( DEFERRED_CHAIN_LENGTH > MAX_DEFERRED_DEPENDENCY_CHAIN_LENGTH )); then
echo "❌ Deferred dependency chain length $DEFERRED_CHAIN_LENGTH > $MAX_DEFERRED_DEPENDENCY_CHAIN_LENGTH threshold"
echo "Chains exceeding threshold:"
grep -E "$DEFERRED_DEEP_CHAIN_PATTERN" $LOG_FILE || echo " (No detailed chains found in log)"
echo "🔧 These chains violate the threshold MAX_DEFERRED_DEPENDENCY_CHAIN_LENGTH. Please refactor them to break these chains."
exit 1
else
echo "✅ No deferred dependency chains exceed the threshold of $MAX_DEFERRED_DEPENDENCY_CHAIN_LENGTH"
fi
- name: Stop application
if: always()
run: kill $(<app.pid) || true