Skip to content

Commit 1cdd827

Browse files
committed
Add pro benchmarks
1 parent 9a0a65d commit 1cdd827

File tree

3 files changed

+220
-36
lines changed

3 files changed

+220
-36
lines changed

.github/workflows/benchmark.yml

Lines changed: 183 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,175 @@ 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 _2.5.4_ check || bundle _2.5.4_ install --jobs=4 --retry=3
386+
387+
- name: Generate file-system based entrypoints for Pro
388+
if: github.event.inputs.app_version != 'core_only'
389+
run: cd react_on_rails_pro/spec/dummy && bundle exec rake react_on_rails:generate_packs
390+
391+
- name: Prepare Pro production assets
392+
if: github.event.inputs.app_version != 'core_only'
340393
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"
394+
set -e
395+
echo "🔨 Building Pro production assets..."
396+
cd react_on_rails_pro/spec/dummy
397+
398+
if ! bin/prod-assets; then
399+
echo "❌ ERROR: Failed to build production assets"
400+
exit 1
401+
fi
402+
403+
echo "✅ Production assets built successfully"
404+
405+
- name: Start Pro production server
406+
if: github.event.inputs.app_version != 'core_only'
407+
run: |
408+
set -e
409+
echo "🚀 Starting Pro production server..."
410+
cd react_on_rails_pro/spec/dummy
411+
412+
# Start server in background
413+
bin/prod &
414+
echo "Server started in background"
415+
416+
# Wait for server to be ready (max 30 seconds)
417+
echo "⏳ Waiting for server to be ready..."
418+
for i in {1..30}; do
419+
if curl -fsS http://localhost:3001 > /dev/null; then
420+
echo "✅ Server is ready and responding"
421+
exit 0
422+
fi
423+
echo " Attempt $i/30: Server not ready yet..."
424+
sleep 1
425+
done
426+
427+
echo "❌ ERROR: Server failed to start within 30 seconds"
428+
exit 1
344429
345430
# ============================================
346-
# WORKFLOW COMPLETION
431+
# STEP 7: RUN PRO BENCHMARKS
347432
# ============================================
348433

434+
- name: Execute Pro benchmark suite
435+
if: github.event.inputs.app_version != 'core_only'
436+
timeout-minutes: 120
437+
run: |
438+
set -e
439+
echo "🏃 Running Pro benchmark suite..."
440+
441+
if ! PRO=true ruby spec/performance/bench.rb; then
442+
echo "❌ ERROR: Benchmark execution failed"
443+
exit 1
444+
fi
445+
446+
echo "✅ Benchmark suite completed successfully"
447+
448+
- name: Validate Pro benchmark results
449+
if: github.event.inputs.app_version != 'core_only'
450+
run: |
451+
set -e
452+
echo "🔍 Validating Pro benchmark output files..."
453+
454+
RESULTS_DIR="bench_results"
455+
REQUIRED_FILES=("summary.txt")
456+
MISSING_FILES=()
457+
458+
if [ ! -d "${RESULTS_DIR}" ]; then
459+
echo "❌ ERROR: Benchmark results directory '${RESULTS_DIR}' not found"
460+
exit 1
461+
fi
462+
463+
echo "Generated files:"
464+
ls -lh ${RESULTS_DIR}/ || true
465+
echo ""
466+
467+
for file in "${REQUIRED_FILES[@]}"; do
468+
if [ ! -f "${RESULTS_DIR}/${file}" ]; then
469+
MISSING_FILES+=("${file}")
470+
fi
471+
done
472+
473+
if [ ${#MISSING_FILES[@]} -eq 0 ]; then
474+
echo "✅ All required benchmark output files present"
475+
echo "📊 Summary preview:"
476+
head -20 ${RESULTS_DIR}/summary.txt || true
477+
else
478+
echo "⚠️ WARNING: Some required files are missing:"
479+
printf ' - %s\n' "${MISSING_FILES[@]}"
480+
echo "Continuing with available results..."
481+
fi
482+
483+
- name: Upload Pro benchmark results
484+
uses: actions/upload-artifact@v4
485+
if: github.event.inputs.app_version != 'core_only' && always()
486+
with:
487+
name: benchmark-pro-results-${{ github.run_number }}
488+
path: bench_results/
489+
retention-days: 30
490+
if-no-files-found: warn
491+
492+
# ============================================
493+
# STEP 8: WORKFLOW COMPLETION
494+
# ============================================
349495
- name: Workflow summary
350496
if: always()
351497
run: |
352498
echo "📋 Benchmark Workflow Summary"
353-
echo "=============================="
499+
echo "===================================="
354500
echo "Status: ${{ job.status }}"
355501
echo "Run number: ${{ github.run_number }}"
356502
echo "Triggered by: ${{ github.actor }}"
357503
echo "Branch: ${{ github.ref_name }}"
504+
echo "App version: ${{ github.event.inputs.app_version || 'both' }}"
358505
echo ""
359506
if [ "${{ job.status }}" == "success" ]; then
360507
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)