@@ -17,10 +17,48 @@ APP_DIR="${REPO_ROOT}/apps/unicorn-store-spring-java25"
1717DOCKERFILES_DIR=" ${REPO_ROOT} /apps/dockerfiles-java25"
1818IMAGE_NAME=" unicorn-store-spring"
1919
20- # Output files (only used in deploy mode)
21- QUEUE_FILE=" ${SCRIPT_DIR} /test-optimizations-queue.txt"
22- RESULTS_FILE=" ${SCRIPT_DIR} /test-optimizations-results.txt"
23- WATCHER_PID_FILE=" ${SCRIPT_DIR} /.watcher.pid"
20+ # Output directory (use /tmp if writable, otherwise script dir)
21+ if [[ -w /tmp ]]; then
22+ OUTPUT_DIR=" /tmp/test-optimizations"
23+ else
24+ OUTPUT_DIR=" ${SCRIPT_DIR} /.test-optimizations"
25+ fi
26+
27+ # Cleanup on exit/interrupt
28+ cleanup () {
29+ local exit_code=$?
30+ log_info " Cleaning up..."
31+
32+ # Kill watcher if running
33+ if [[ -f " ${WATCHER_PID_FILE} " ]]; then
34+ local pid=$( cat " ${WATCHER_PID_FILE} " )
35+ kill " $pid " 2> /dev/null || true
36+ rm -f " ${WATCHER_PID_FILE} "
37+ fi
38+
39+ # Stop build database if running
40+ docker rm -f build-postgres 2> /dev/null || true
41+
42+ # Restore UnicornPublisher if backup exists
43+ if [[ -f " ${APP_DIR} /src/main/java/com/unicorn/store/data/UnicornPublisher.java.orig" ]]; then
44+ mv " ${APP_DIR} /src/main/java/com/unicorn/store/data/UnicornPublisher.java.orig" \
45+ " ${APP_DIR} /src/main/java/com/unicorn/store/data/UnicornPublisher.java"
46+ fi
47+
48+ # Revert deployment to baseline if in deploy mode (disabled for testing)
49+ # if [[ "$DEPLOY_MODE" == true && -n "$ACCOUNT_ID" ]]; then
50+ # log_info "Reverting deployment to :latest..."
51+ # local ecr_uri="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${IMAGE_NAME}"
52+ # kubectl set image deployment/unicorn-store-spring \
53+ # unicorn-store-spring="${ecr_uri}:latest" -n unicorn-store-spring 2>/dev/null || true
54+ # fi
55+
56+ exit $exit_code
57+ }
58+ trap cleanup EXIT INT TERM
59+ QUEUE_FILE=" ${OUTPUT_DIR} /queue.txt"
60+ RESULTS_FILE=" ${OUTPUT_DIR} /results.txt"
61+ WATCHER_PID_FILE=" ${OUTPUT_DIR} /watcher.pid"
2462
2563# Methods in order (tag names)
2664METHODS=(
@@ -125,6 +163,7 @@ format_time() {
125163# Build single image
126164build_image () {
127165 local tag=" $1 "
166+ local log_file=" $2 "
128167 local dockerfile=" ${DOCKERFILES_DIR} /Dockerfile.${tag} "
129168 local build_args=" "
130169
@@ -133,13 +172,14 @@ build_image() {
133172 # Special case: jib uses maven
134173 if [[ " $tag " == " 03-jib" ]]; then
135174 log_info " Using Maven Jib plugin..."
136- (cd " ${APP_DIR} " && mvn compile jib:dockerBuild -Dimage=${IMAGE_NAME} :${tag} -q)
175+ (cd " ${APP_DIR} " && mvn compile jib:dockerBuild -Dimage=${IMAGE_NAME} :${tag} ) >> " ${log_file} " 2>&1
137176 return $?
138177 fi
139178
140179 # Check Dockerfile exists
141180 if [[ ! -f " ${dockerfile} " ]]; then
142181 log_error " Dockerfile not found: ${dockerfile} "
182+ echo " ERROR: Dockerfile not found: ${dockerfile} " >> " ${log_file} "
143183 return 1
144184 fi
145185
@@ -156,9 +196,14 @@ build_image() {
156196 build_args=" ${build_args} --build-arg SPRING_DATASOURCE_PASSWORD=unicorn"
157197 fi
158198
159- # Build
199+ # Build with --progress=plain for cleaner logs
200+ # Use --no-cache for methods that need fresh training (CDS, AOT, CRaC)
201+ local no_cache=" "
202+ if needs_db " $tag " ; then
203+ no_cache=" --no-cache"
204+ fi
160205 local result=0
161- docker build ${ build_args} -f " ${dockerfile} " -t " ${IMAGE_NAME} :${tag} " " ${APP_DIR} " || result=$?
206+ docker build --progress=plain ${no_cache} ${ build_args} -f " ${dockerfile} " -t " ${IMAGE_NAME} :${tag} " " ${APP_DIR} " >> " ${log_file} " 2>&1 || result=$?
162207
163208 # Cleanup
164209 if needs_db " $tag " ; then
@@ -174,18 +219,31 @@ build_image() {
174219}
175220
176221# Push image to ECR and return ECR size
222+ # Returns: "SIZE" on success, "PUSH_FAILED:reason" on failure
177223push_image () {
178224 local tag=" $1 "
225+ local log_file=" $2 "
179226 local ecr_uri=" ${ACCOUNT_ID} .dkr.ecr.${AWS_REGION} .amazonaws.com/${IMAGE_NAME} "
180227
228+ echo " === PUSH ${tag} ===" >> " ${log_file} "
181229 docker tag " ${IMAGE_NAME} :${tag} " " ${ecr_uri} :${tag} "
182- docker push " ${ecr_uri} :${tag} "
230+
231+ # Capture push output for error reporting and logging
232+ local push_output
233+ if ! push_output=$( docker push " ${ecr_uri} :${tag} " 2>&1 ) ; then
234+ echo " $push_output " >> " ${log_file} "
235+ # Extract last meaningful error line
236+ local error_msg=$( echo " $push_output " | grep -iE ' (error|denied|failed|unauthorized)' | tail -1 | cut -c1-50)
237+ echo " PUSH_FAILED:${error_msg:- push failed} "
238+ return 1
239+ fi
240+ echo " $push_output " >> " ${log_file} "
183241
184242 # SOCI index for soci method
185243 if [[ " $tag " == " 05-soci" ]]; then
186- log_info " Creating SOCI index... "
187- sudo soci create " ${ecr_uri} :${tag} " 2> /dev/null || true
188- sudo soci push " ${ecr_uri} :${tag} " 2> /dev/null || true
244+ echo " === SOCI INDEX === " >> " ${log_file} "
245+ sudo soci create " ${ecr_uri} :${tag} " >> " ${log_file} " 2>&1 || true
246+ sudo soci push " ${ecr_uri} :${tag} " >> " ${log_file} " 2>&1 || true
189247 fi
190248
191249 # Get ECR image size
@@ -211,8 +269,8 @@ deploy_watcher() {
211269 local ecr_uri=" ${ACCOUNT_ID} .dkr.ecr.${AWS_REGION} .amazonaws.com/${IMAGE_NAME} "
212270
213271 # Initialize results file
214- echo " Method | Size Local | Size ECR | Build Time | Startup Time | Restart Time " > " ${RESULTS_FILE} "
215- echo " -------|------------|----------|------------|--------------|------------- " >> " ${RESULTS_FILE} "
272+ echo " Method | Size Local | Size ECR | Build Time | Startup Time" > " ${RESULTS_FILE} "
273+ echo " -------|------------|----------|------------|-------------" >> " ${RESULTS_FILE} "
216274
217275 local last_line_num=0
218276
@@ -228,41 +286,46 @@ deploy_watcher() {
228286
229287 # Check for END marker
230288 if [[ " $status " == " END" ]]; then
231- # Revert to baseline
232- log_info " Reverting to baseline (:latest)..."
233- kubectl set image deployment/unicorn-store-spring \
234- unicorn-store-spring=" ${ecr_uri} :latest" -n unicorn-store-spring 2> /dev/null
235- kubectl rollout status deployment unicorn-store-spring -n unicorn-store-spring --timeout=180s 2> /dev/null
289+ # Revert to baseline (disabled for testing)
290+ # log_info "Reverting to baseline (:latest)..."
291+ # kubectl set image deployment/unicorn-store-spring \
292+ # unicorn-store-spring="${ecr_uri}:latest" -n unicorn-store-spring 2>/dev/null
293+ # kubectl rollout status deployment unicorn-store-spring -n unicorn-store-spring --timeout=180s 2>/dev/null
236294 return 0
237295 fi
238296
239- # Handle failed builds
297+ local deploy_log=" ${OUTPUT_DIR} /${tag} -deploy.txt"
298+ echo " === DEPLOY ${tag} ===" > " ${deploy_log} "
299+
300+ # Handle failed builds/pushes
240301 if [[ " $status " == " FAILED" ]]; then
241- echo " ${tag} | ${size_local:- N/ A} | ${size_ecr:- N/ A} | ${build_time:- N/ A} | BUILD FAILED | -" >> " ${RESULTS_FILE} "
302+ local fail_reason=" ${error_msg:- BUILD FAILED} "
303+ echo " ${tag} | ${size_local:- N/ A} | ${size_ecr:- N/ A} | ${build_time:- N/ A} | ${fail_reason} " >> " ${RESULTS_FILE} "
304+ echo " Skipped: ${fail_reason} " >> " ${deploy_log} "
305+ log_info " ${tag} : ${fail_reason} "
242306 continue
243307 fi
244308
245- # Deploy with new image (cold start)
309+ # Deploy with new image
246310 log_info " Deploying ${tag} ..."
311+ echo " --- kubectl set image ---" >> " ${deploy_log} "
247312 kubectl set image deployment/unicorn-store-spring \
248- unicorn-store-spring=" ${ecr_uri} :${tag} " -n unicorn-store-spring 2> /dev/null
249- if ! kubectl rollout status deployment unicorn-store-spring -n unicorn-store-spring --timeout=180s 2> /dev/null; then
250- echo " ${tag} | ${size_local} | ${size_ecr} | ${build_time} | DEPLOY FAILED | -" >> " ${RESULTS_FILE} "
313+ unicorn-store-spring=" ${ecr_uri} :${tag} " -n unicorn-store-spring >> " ${deploy_log} " 2>&1
314+ echo " --- kubectl rollout status ---" >> " ${deploy_log} "
315+ if ! kubectl rollout status deployment unicorn-store-spring -n unicorn-store-spring --timeout=180s >> " ${deploy_log} " 2>&1 ; then
316+ echo " --- kubectl describe deployment ---" >> " ${deploy_log} "
317+ kubectl describe deployment unicorn-store-spring -n unicorn-store-spring >> " ${deploy_log} " 2>&1
318+ echo " --- kubectl get events ---" >> " ${deploy_log} "
319+ kubectl get events -n unicorn-store-spring --sort-by=' .lastTimestamp' | tail -20 >> " ${deploy_log} " 2>&1
320+ echo " ${tag} | ${size_local} | ${size_ecr} | ${build_time} | DEPLOY FAILED" >> " ${RESULTS_FILE} "
251321 continue
252322 fi
253323 sleep 15
254324 local startup_time=$( get_startup_time " $tag " )
325+ echo " Startup time: ${startup_time} " >> " ${deploy_log} "
255326
256- # Restart (warm restart)
257- kubectl rollout restart deployment unicorn-store-spring -n unicorn-store-spring 2> /dev/null
258- local restart_time=" RESTART FAILED"
259- if kubectl rollout status deployment unicorn-store-spring -n unicorn-store-spring --timeout=180s 2> /dev/null; then
260- sleep 15
261- restart_time=$( get_startup_time " $tag " )
262- fi
263-
264- echo " ${tag} | ${size_local} | ${size_ecr} | ${build_time} | ${startup_time} | ${restart_time} " >> " ${RESULTS_FILE} "
265- log_info " ${tag} : startup=${startup_time} , restart=${restart_time} "
327+ echo " ${tag} | ${size_local} | ${size_ecr} | ${build_time} | ${startup_time} " >> " ${RESULTS_FILE} "
328+ log_info " ${tag} : startup=${startup_time} "
266329 done
267330 fi
268331
@@ -272,10 +335,6 @@ deploy_watcher() {
272335
273336# Start deploy watcher in background
274337start_watcher () {
275- # Clean up old files
276- rm -f " ${QUEUE_FILE} " " ${RESULTS_FILE} " " ${WATCHER_PID_FILE} "
277- touch " ${QUEUE_FILE} "
278-
279338 # Start watcher in background
280339 deploy_watcher &
281340 echo $! > " ${WATCHER_PID_FILE} "
@@ -292,22 +351,28 @@ wait_for_watcher() {
292351 fi
293352}
294353
295- # Write to queue
354+ # Write to queue (atomic write to avoid race conditions)
296355queue_build_result () {
297356 local status=" $1 "
298357 local tag=" $2 "
299358 local size_local=" $3 "
300359 local size_ecr=" $4 "
301360 local build_time=" $5 "
302- local error_msg=" $6 "
361+ local error_msg=" ${6 :- } "
303362
304- if [[ " $status " == " OK" ]]; then
305- echo " OK|${tag} |${size_local} |${size_ecr} |${build_time} |" >> " ${QUEUE_FILE} "
306- else
307- echo " FAILED|${tag} |${size_local} |${size_ecr} |${build_time} |${error_msg} " >> " ${QUEUE_FILE} "
308- fi
363+ # Sanitize fields - remove newlines and limit length
364+ size_ecr=$( echo " $size_ecr " | tr -d ' \n' | head -c 20)
365+ error_msg=$( echo " $error_msg " | tr -d ' \n' | head -c 50)
366+
367+ # Use consistent format: status|tag|size_local|size_ecr|build_time|error_msg
368+ echo " ${status} |${tag} |${size_local} |${size_ecr} |${build_time} |${error_msg} " >> " ${QUEUE_FILE} "
309369}
310370
371+ # Initialize output directory
372+ rm -rf " ${OUTPUT_DIR} "
373+ mkdir -p " ${OUTPUT_DIR} "
374+ log_info " Output: ${OUTPUT_DIR} "
375+
311376# Initialize deploy mode
312377if [[ " $DEPLOY_MODE " == true ]]; then
313378 log_info " Deploy mode enabled - will push to ECR and deploy to EKS"
@@ -324,7 +389,8 @@ if [[ "$DEPLOY_MODE" == true ]]; then
324389 aws ecr get-login-password --region " ${AWS_REGION} " \
325390 | docker login --username AWS --password-stdin " ${ACCOUNT_ID} .dkr.ecr.${AWS_REGION} .amazonaws.com"
326391
327- # Start deploy watcher in background
392+ # Initialize queue and start deploy watcher
393+ touch " ${QUEUE_FILE} "
328394 start_watcher
329395fi
330396
@@ -343,17 +409,29 @@ for tag in "${METHODS[@]}"; do
343409 start_time=$( date +%s)
344410
345411 build_status=" ❌"
412+ push_status=" OK"
346413 size_local=" N/A"
347414 size_ecr=" N/A"
415+ error_msg=" "
348416
349- if build_image " $tag " > /dev/null 2>&1 ; then
417+ build_log=" ${OUTPUT_DIR} /${tag} -build.txt"
418+
419+ if build_image " $tag " " $build_log " ; then
350420 build_status=" ✅"
351421 size_local=$( docker images " ${IMAGE_NAME} :${tag} " --format " {{.Size}}" 2> /dev/null || echo " N/A" )
352422
353423 # Deploy mode: push and queue for deployment
354424 if [[ " $DEPLOY_MODE " == true ]]; then
355- size_ecr=$( push_image " $tag " 2> /dev/null)
425+ size_ecr=$( push_image " $tag " " $build_log " )
426+ # Check if push failed
427+ if [[ " $size_ecr " == PUSH_FAILED:* ]]; then
428+ error_msg=" ${size_ecr# PUSH_FAILED: } "
429+ size_ecr=" N/A"
430+ push_status=" FAILED"
431+ fi
356432 fi
433+ else
434+ error_msg=" Build failed"
357435 fi
358436
359437 end_time=$( date +%s)
@@ -369,10 +447,10 @@ for tag in "${METHODS[@]}"; do
369447
370448 # Queue for deploy watcher
371449 if [[ " $DEPLOY_MODE " == true ]]; then
372- if [[ " $build_status " == " ✅" ]]; then
450+ if [[ " $build_status " == " ✅" && " $push_status " == " OK " ]]; then
373451 queue_build_result " OK" " $tag " " $size_local " " $size_ecr " " $elapsed_fmt "
374452 else
375- queue_build_result " FAILED" " $tag " " $size_local " " $size_ecr " " $elapsed_fmt " " Build failed "
453+ queue_build_result " FAILED" " $tag " " $size_local " " $size_ecr " " $elapsed_fmt " " $error_msg "
376454 fi
377455 fi
378456done
@@ -388,4 +466,4 @@ if [[ "$DEPLOY_MODE" == true ]]; then
388466fi
389467
390468echo " "
391- log_info " Complete"
469+ log_info " Complete (logs: ${OUTPUT_DIR} ) "
0 commit comments