Skip to content

Commit bf8c870

Browse files
committed
Add pro benchmarks
1 parent 8771608 commit bf8c870

File tree

3 files changed

+221
-36
lines changed

3 files changed

+221
-36
lines changed

.github/workflows/benchmark.yml

Lines changed: 184 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,33 +29,34 @@ on:
2929
default: '60s'
3030
type: string
3131
connections:
32-
description: 'Concurrent connections/virtual users'
32+
description: 'Concurrent connections/virtual users (also used as max)'
3333
required: false
3434
default: 10
3535
type: number
36-
max_connections:
37-
description: 'Maximum connections/virtual users'
38-
required: false
39-
type: number
4036
web_concurrency:
4137
description: 'Number of Puma worker processes'
4238
required: false
4339
default: 4
4440
type: number
45-
rails_max_threads:
46-
description: 'Maximum number of Puma threads'
41+
rails_threads:
42+
description: 'Number of Puma threads (min and max will be same)'
4743
required: false
4844
default: 3
4945
type: number
50-
rails_min_threads:
51-
description: 'Minimum number of Puma threads (same as maximum if not set)'
52-
required: false
53-
type: number
5446
tools:
5547
description: 'Comma-separated list of tools to run'
5648
required: false
5749
default: 'fortio,vegeta,k6'
5850
type: string
51+
app_version:
52+
description: 'Which app version to benchmark'
53+
required: false
54+
default: 'both'
55+
type: choice
56+
options:
57+
- 'both'
58+
- 'core_only'
59+
- 'pro_only'
5960
push:
6061
branches:
6162
- master
@@ -71,15 +72,17 @@ env:
7172
DURATION: ${{ github.event.inputs.duration || '30s' }}
7273
REQUEST_TIMEOUT: ${{ github.event.inputs.request_timeout || '60s' }}
7374
CONNECTIONS: ${{ github.event.inputs.connections || 10 }}
74-
MAX_CONNECTIONS: ${{ github.event.inputs.max_connections || github.event.inputs.connections || 10 }}
75+
MAX_CONNECTIONS: ${{ github.event.inputs.connections || 10 }}
7576
WEB_CONCURRENCY: ${{ github.event.inputs.web_concurrency || 4 }}
76-
RAILS_MAX_THREADS: ${{ github.event.inputs.rails_max_threads || 3 }}
77-
RAILS_MIN_THREADS: ${{ github.event.inputs.rails_min_threads || github.event.inputs.rails_max_threads || 3 }}
77+
RAILS_MAX_THREADS: ${{ github.event.inputs.rails_threads || 3 }}
78+
RAILS_MIN_THREADS: ${{ github.event.inputs.rails_threads || 3 }}
7879
TOOLS: ${{ github.event.inputs.tools || 'fortio,vegeta,k6' }}
7980

8081
jobs:
8182
benchmark:
8283
runs-on: ubuntu-latest
84+
env:
85+
REACT_ON_RAILS_PRO_LICENSE: ${{ secrets.REACT_ON_RAILS_PRO_LICENSE }}
8386

8487
steps:
8588
# ============================================
@@ -176,8 +179,8 @@ jobs:
176179
- name: Setup Ruby
177180
uses: ruby/setup-ruby@v1
178181
with:
179-
ruby-version: '3.4'
180-
bundler: 2.5.9
182+
ruby-version: '3.3.7'
183+
bundler: 2.5.4
181184

182185
- name: Fix dependency for libyaml-dev
183186
run: sudo apt install libyaml-dev -y
@@ -208,29 +211,34 @@ jobs:
208211
run: cd packages/react-on-rails && yarn install --no-progress --no-emoji --frozen-lockfile && yalc publish
209212

210213
- name: yalc add react-on-rails
214+
if: github.event.inputs.app_version != 'pro_only'
211215
run: cd spec/dummy && yalc add react-on-rails
212216

213217
- name: Install Node modules with Yarn for dummy app
218+
if: github.event.inputs.app_version != 'pro_only'
214219
run: cd spec/dummy && yarn install --no-progress --no-emoji
215220

216221
- name: Save dummy app ruby gems to cache
222+
if: github.event.inputs.app_version != 'pro_only'
217223
uses: actions/cache@v4
218224
with:
219225
path: spec/dummy/vendor/bundle
220226
key: dummy-app-gem-cache-${{ hashFiles('spec/dummy/Gemfile.lock') }}
221227

222228
- name: Install Ruby Gems for dummy app
229+
if: github.event.inputs.app_version != 'pro_only'
223230
run: |
224231
cd spec/dummy
225232
bundle lock --add-platform 'x86_64-linux'
226233
if ! bundle check --path=vendor/bundle; then
227-
bundle _2.5.9_ install --path=vendor/bundle --jobs=4 --retry=3
234+
bundle _2.5.4_ install --path=vendor/bundle --jobs=4 --retry=3
228235
fi
229236
230237
- name: generate file system-based packs
231238
run: cd spec/dummy && RAILS_ENV="production" bundle exec rake react_on_rails:generate_packs
232239

233240
- name: Prepare production assets
241+
if: github.event.inputs.app_version != 'pro_only'
234242
run: |
235243
set -e # Exit on any error
236244
echo "🔨 Building production assets..."
@@ -244,6 +252,7 @@ jobs:
244252
echo "✅ Production assets built successfully"
245253
246254
- name: Start production server
255+
if: github.event.inputs.app_version != 'pro_only'
247256
run: |
248257
set -e # Exit on any error
249258
echo "🚀 Starting production server..."
@@ -268,14 +277,15 @@ jobs:
268277
exit 1
269278
270279
# ============================================
271-
# STEP 5: RUN BENCHMARKS
280+
# STEP 5: RUN CORE BENCHMARKS
272281
# ============================================
273282

274-
- name: Execute benchmark suite
275-
timeout-minutes: 20
283+
- name: Execute Core benchmark suite
284+
if: github.event.inputs.app_version != 'pro_only'
285+
timeout-minutes: 120
276286
run: |
277287
set -e # Exit on any error
278-
echo "🏃 Running benchmark suite..."
288+
echo "🏃 Running Core benchmark suite..."
279289
280290
if ! ruby spec/performance/bench.rb; then
281291
echo "❌ ERROR: Benchmark execution failed"
@@ -284,7 +294,8 @@ jobs:
284294
285295
echo "✅ Benchmark suite completed successfully"
286296
287-
- name: Validate benchmark results
297+
- name: Validate Core benchmark results
298+
if: github.event.inputs.app_version != 'pro_only'
288299
run: |
289300
set -e # Exit on any error
290301
echo "🔍 Validating benchmark output files..."
@@ -322,39 +333,176 @@ jobs:
322333
echo "Continuing with available results..."
323334
fi
324335
325-
# ============================================
326-
# STEP 6: COLLECT BENCHMARK RESULTS
327-
# ============================================
328-
329-
- name: Upload benchmark results
336+
- name: Upload Core benchmark results
330337
uses: actions/upload-artifact@v4
331-
if: always() # Upload even if benchmark fails
338+
if: github.event.inputs.app_version != 'pro_only' && always()
332339
with:
333-
name: benchmark-results-${{ github.run_number }}
340+
name: benchmark-core-results-${{ github.run_number }}
334341
path: bench_results/
335342
retention-days: 30
336343
if-no-files-found: warn
337344

338-
- name: Verify artifact upload
339-
if: success()
345+
# ============================================
346+
# STEP 6: SETUP PRO APPLICATION SERVER
347+
# ============================================
348+
- name: Cache Pro package node modules
349+
if: github.event.inputs.app_version != 'core_only'
350+
uses: actions/cache@v4
351+
with:
352+
path: react_on_rails_pro/node_modules
353+
key: v4-pro-package-node-modules-cache-${{ hashFiles('react_on_rails_pro/yarn.lock') }}
354+
355+
- name: Cache Pro dummy app node modules
356+
if: github.event.inputs.app_version != 'core_only'
357+
uses: actions/cache@v4
358+
with:
359+
path: react_on_rails_pro/spec/dummy/node_modules
360+
key: v4-pro-dummy-app-node-modules-cache-${{ hashFiles('react_on_rails_pro/spec/dummy/yarn.lock') }}
361+
362+
- name: Cache Pro dummy app Ruby gems
363+
if: github.event.inputs.app_version != 'core_only'
364+
uses: actions/cache@v4
365+
with:
366+
path: react_on_rails_pro/spec/dummy/vendor/bundle
367+
key: v4-pro-dummy-app-gem-cache-${{ hashFiles('react_on_rails_pro/spec/dummy/Gemfile.lock') }}
368+
369+
- name: Install Node modules with Yarn for Pro package
370+
if: github.event.inputs.app_version != 'core_only'
371+
run: |
372+
cd react_on_rails_pro
373+
sudo yarn global add yalc
374+
yarn install --frozen-lockfile --no-progress --no-emoji
375+
376+
- name: Install Node modules with Yarn for Pro dummy app
377+
if: github.event.inputs.app_version != 'core_only'
378+
run: cd react_on_rails_pro/spec/dummy && yarn install --frozen-lockfile --no-progress --no-emoji
379+
380+
- name: Install Ruby Gems for Pro dummy app
381+
if: github.event.inputs.app_version != 'core_only'
382+
run: |
383+
cd react_on_rails_pro/spec/dummy
384+
bundle lock --add-platform 'x86_64-linux'
385+
bundle config set path vendor/bundle
386+
bundle _2.5.4_ check || bundle _2.5.4_ install --jobs=4 --retry=3
387+
388+
- name: Generate file-system based entrypoints for Pro
389+
if: github.event.inputs.app_version != 'core_only'
390+
run: cd react_on_rails_pro/spec/dummy && bundle exec rake react_on_rails:generate_packs
391+
392+
- name: Prepare Pro production assets
393+
if: github.event.inputs.app_version != 'core_only'
340394
run: |
341-
echo "✅ Benchmark results uploaded as workflow artifacts"
342-
echo "📦 Artifact name: benchmark-results-${{ github.run_number }}"
343-
echo "🔗 Access artifacts from the Actions tab in GitHub"
395+
set -e
396+
echo "🔨 Building Pro production assets..."
397+
cd react_on_rails_pro/spec/dummy
398+
399+
if ! bin/prod-assets; then
400+
echo "❌ ERROR: Failed to build production assets"
401+
exit 1
402+
fi
403+
404+
echo "✅ Production assets built successfully"
405+
406+
- name: Start Pro production server
407+
if: github.event.inputs.app_version != 'core_only'
408+
run: |
409+
set -e
410+
echo "🚀 Starting Pro production server..."
411+
cd react_on_rails_pro/spec/dummy
412+
413+
# Start server in background
414+
bin/prod &
415+
echo "Server started in background"
416+
417+
# Wait for server to be ready (max 30 seconds)
418+
echo "⏳ Waiting for server to be ready..."
419+
for i in {1..30}; do
420+
if curl -fsS http://localhost:3001 > /dev/null; then
421+
echo "✅ Server is ready and responding"
422+
exit 0
423+
fi
424+
echo " Attempt $i/30: Server not ready yet..."
425+
sleep 1
426+
done
427+
428+
echo "❌ ERROR: Server failed to start within 30 seconds"
429+
exit 1
344430
345431
# ============================================
346-
# WORKFLOW COMPLETION
432+
# STEP 7: RUN PRO BENCHMARKS
347433
# ============================================
348434

435+
- name: Execute Pro benchmark suite
436+
if: github.event.inputs.app_version != 'core_only'
437+
timeout-minutes: 120
438+
run: |
439+
set -e
440+
echo "🏃 Running Pro benchmark suite..."
441+
442+
if ! PRO=true ruby spec/performance/bench.rb; then
443+
echo "❌ ERROR: Benchmark execution failed"
444+
exit 1
445+
fi
446+
447+
echo "✅ Benchmark suite completed successfully"
448+
449+
- name: Validate Pro benchmark results
450+
if: github.event.inputs.app_version != 'core_only'
451+
run: |
452+
set -e
453+
echo "🔍 Validating Pro benchmark output files..."
454+
455+
RESULTS_DIR="bench_results"
456+
REQUIRED_FILES=("summary.txt")
457+
MISSING_FILES=()
458+
459+
if [ ! -d "${RESULTS_DIR}" ]; then
460+
echo "❌ ERROR: Benchmark results directory '${RESULTS_DIR}' not found"
461+
exit 1
462+
fi
463+
464+
echo "Generated files:"
465+
ls -lh ${RESULTS_DIR}/ || true
466+
echo ""
467+
468+
for file in "${REQUIRED_FILES[@]}"; do
469+
if [ ! -f "${RESULTS_DIR}/${file}" ]; then
470+
MISSING_FILES+=("${file}")
471+
fi
472+
done
473+
474+
if [ ${#MISSING_FILES[@]} -eq 0 ]; then
475+
echo "✅ All required benchmark output files present"
476+
echo "📊 Summary preview:"
477+
head -20 ${RESULTS_DIR}/summary.txt || true
478+
else
479+
echo "⚠️ WARNING: Some required files are missing:"
480+
printf ' - %s\n' "${MISSING_FILES[@]}"
481+
echo "Continuing with available results..."
482+
fi
483+
484+
- name: Upload Pro benchmark results
485+
uses: actions/upload-artifact@v4
486+
if: github.event.inputs.app_version != 'core_only' && always()
487+
with:
488+
name: benchmark-pro-results-${{ github.run_number }}
489+
path: bench_results/
490+
retention-days: 30
491+
if-no-files-found: warn
492+
493+
# ============================================
494+
# STEP 8: WORKFLOW COMPLETION
495+
# ============================================
349496
- name: Workflow summary
350497
if: always()
351498
run: |
352499
echo "📋 Benchmark Workflow Summary"
353-
echo "=============================="
500+
echo "===================================="
354501
echo "Status: ${{ job.status }}"
355502
echo "Run number: ${{ github.run_number }}"
356503
echo "Triggered by: ${{ github.actor }}"
357504
echo "Branch: ${{ github.ref_name }}"
505+
echo "App version: ${{ github.event.inputs.app_version || 'both' }}"
358506
echo ""
359507
if [ "${{ job.status }}" == "success" ]; then
360508
echo "✅ All steps completed successfully"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
3+
# Run only after ./prod-assets
4+
5+
# Check if assets are precompiled
6+
MANIFEST="public/webpack/production/manifest.json"
7+
8+
if [ ! -d "public/assets" ]; then
9+
echo "ERROR: public/assets not found. Run ./bin/prod-assets first"
10+
exit 1
11+
fi
12+
13+
if [ ! -f "$MANIFEST" ]; then
14+
echo "ERROR: $MANIFEST not found. Run ./bin/prod-assets first"
15+
exit 1
16+
fi
17+
18+
# Simple up-to-date check: warn if source files are newer than manifest.json
19+
if find client config -type f \( -name "*.[jt]s" -o -name "*.[jt]sx" \) -newer "$MANIFEST" 2>/dev/null | grep -q .; then
20+
echo "WARNING: client or config has changes newer than compiled assets"
21+
echo "Consider running ./bin/prod-assets to rebuild"
22+
fi
23+
24+
if [ -f "yarn.lock" ] && [ "yarn.lock" -nt "$MANIFEST" ]; then
25+
echo "WARNING: yarn.lock is newer than compiled assets"
26+
echo "Consider running ./bin/prod-assets to rebuild"
27+
fi
28+
29+
NODE_ENV=production RAILS_ENV=production bundle exec rails server -p 3001
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
export NODE_ENV=production
4+
export RAILS_ENV=production
5+
if [ "$CI" = "true" ]; then
6+
bundle exec bootsnap precompile --gemfile app/ lib/ config/
7+
fi
8+
bundle exec rails assets:precompile

0 commit comments

Comments
 (0)