Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
997e8c9
Initial benchmark version
alexeyr Sep 22, 2025
aefdd45
Add production scripts
alexeyr Oct 2, 2025
ff07444
Initial benchmark workflow
alexeyr Oct 3, 2025
613e60d
Add server warm-up to benchmark
alexeyr Nov 5, 2025
a8c6d79
Make request timeout a parameter
alexeyr Nov 5, 2025
faa516a
Update defaults for now
alexeyr Nov 5, 2025
3d043e1
Fix knip error
alexeyr Nov 5, 2025
f2798cb
Enable clustered mode in production
alexeyr Nov 5, 2025
bfab144
Add MAX_CONNECTIONS
alexeyr Nov 5, 2025
1f8d8c9
Fix max rate K6 scenario
alexeyr Nov 5, 2025
1d57366
Reorder workflow parameters more logically
alexeyr Nov 5, 2025
67591ab
Closer to recommended Fortio options
alexeyr Nov 5, 2025
2b487c4
Allow configuring RAILS_MAX/MIN_THREADS in the workflow
alexeyr Nov 5, 2025
fcdae78
Move showing benchmark params to bench.sh for simplicity
alexeyr Nov 5, 2025
1da9b65
Convert the benchmark script to Ruby
alexeyr Nov 7, 2025
9245e5a
Fix k6 timeout
alexeyr Nov 7, 2025
2bbba04
Replace DURATION_SEC with DURATION
alexeyr Nov 7, 2025
b4051b2
Group all code for a tool into a single block
alexeyr Nov 7, 2025
af2dedb
Remove duplication in adding summaries
alexeyr Nov 7, 2025
bea93c9
Benchmark all routes
alexeyr Nov 8, 2025
b16a9fe
Fix Fortio failure on server_side_log_throw_raise
alexeyr Nov 8, 2025
c769479
Allow specifying routes
alexeyr Nov 8, 2025
bbd3b30
Add pro benchmarks
alexeyr Nov 8, 2025
05f5486
Update Claude instructions
alexeyr Nov 8, 2025
5e57254
FIXME temp commit
alexeyr Nov 11, 2025
6dbee4e
Update prod-assets to include generate_packs
alexeyr Nov 11, 2025
7a4ef8b
Disable js_compressor and css_compressor
alexeyr Nov 11, 2025
fb7dc80
Remove unused pg gem
alexeyr Nov 11, 2025
7c1e71f
Handle empty inputs correctly
alexeyr Nov 11, 2025
c941461
Fix app version handling in the benchmark workflow
alexeyr Nov 11, 2025
e204c63
Fix starting/stopping servers
alexeyr Nov 11, 2025
aa5f224
Simplify validate steps
alexeyr Nov 12, 2025
1086d92
Temp config to speed up
alexeyr Nov 12, 2025
a623ef6
Optimize tools installation
alexeyr Nov 12, 2025
26d6bc7
Add logging to server check
alexeyr Nov 12, 2025
cd588ac
Make installs frozen
alexeyr Nov 12, 2025
1f987a6
Allow redirects in server_responding
alexeyr Nov 12, 2025
5b096f8
Try full Pro benchmark
alexeyr Nov 12, 2025
a3b60f1
Update Core dummy path
alexeyr Dec 1, 2025
5bcbb49
Temporary root RuboCop config
alexeyr Dec 1, 2025
5145481
Update Gemfile.lock
alexeyr Dec 4, 2025
0c899c1
Switch benchmark.yml to pnpm and new directory structure
alexeyr Dec 2, 2025
176abf1
generate_packs is now needed in core as well
alexeyr Dec 4, 2025
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
526 changes: 526 additions & 0 deletions .github/workflows/benchmark.yml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ react_on_rails/spec/dummy/**/*.res.js
react_on_rails_pro/spec/dummy/.bsb.lock
react_on_rails_pro/spec/dummy/**/*.res.js

# Performance test results
/bench_results

# Generated by ROR FS-based Registry
generated

Expand Down
9 changes: 9 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Root config reuses the one from react_on_rails for now,
# later it should be the other way around
inherit_from: react_on_rails/.rubocop.yml

AllCops:
Exclude:
- 'gen-examples/**/*'
- 'react_on_rails/**/*'
- 'react_on_rails_pro/**/*'
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ Pre-commit hooks automatically run:
- All linters: `rake lint` (runs ESLint and RuboCop)
- ESLint only: `pnpm run lint` or `rake lint:eslint`
- RuboCop only: `rake lint:rubocop`
- GitHub Action files (workflows, reusable actions, etc.): `actionlint`
- YAML files: `yamllint` (or validate the syntax with Ruby if it isn't installed). Do _not_ try to run RuboCop on `.yml` files.
- **Code Formatting**:
- Format code with Prettier: `rake autofix`
- Check formatting without fixing: `pnpm run format.listDifferent`
Expand Down
2 changes: 2 additions & 0 deletions knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const config: KnipConfig = {
// Pro package binaries used in Pro workflows
'playwright',
'e2e-test',
// Local binaries
'bin/.*',
],
ignore: ['react_on_rails_pro/**', 'react_on_rails/vendor/**'],
ignoreDependencies: [
Expand Down
7 changes: 5 additions & 2 deletions react_on_rails/spec/dummy/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ GEM
nokogiri (1.18.10)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.18.10-x86_64-linux-gnu)
racc (~> 1.4)
ostruct (0.6.3)
package_json (0.1.0)
parallel (1.24.0)
Expand Down Expand Up @@ -345,7 +347,7 @@ GEM
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semantic_range (3.1.0)
shakapacker (9.3.0)
shakapacker (9.4.0)
activesupport (>= 5.2)
package_json
rack-proxy (>= 0.6.1)
Expand Down Expand Up @@ -423,6 +425,7 @@ GEM

PLATFORMS
ruby
x86_64-linux

DEPENDENCIES
amazing_print
Expand Down Expand Up @@ -461,7 +464,7 @@ DEPENDENCIES
sass-rails (~> 6.0)
sdoc
selenium-webdriver (= 4.9.0)
shakapacker (= 9.3.0)
shakapacker (= 9.4.0)
spring (~> 4.0)
sprockets (~> 4.0)
sqlite3 (~> 1.6)
Expand Down
29 changes: 29 additions & 0 deletions react_on_rails/spec/dummy/bin/prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash

# Run only after ./prod-assets

# Check if assets are precompiled
MANIFEST="public/webpack/production/manifest.json"

if [ ! -d "public/assets" ]; then
echo "ERROR: public/assets not found. Run ./bin/prod-assets first"
exit 1
fi

if [ ! -f "$MANIFEST" ]; then
echo "ERROR: $MANIFEST not found. Run ./bin/prod-assets first"
exit 1
fi

# Simple up-to-date check: warn if source files are newer than manifest.json
if find client config -type f \( -name "*.[jt]s" -o -name "*.[jt]sx" \) -newer "$MANIFEST" 2>/dev/null | grep -q .; then
echo "WARNING: client or config has changes newer than compiled assets"
echo "Consider running ./bin/prod-assets to rebuild"
fi

if [ -f "yarn.lock" ] && [ "yarn.lock" -nt "$MANIFEST" ]; then
echo "WARNING: yarn.lock is newer than compiled assets"
echo "Consider running ./bin/prod-assets to rebuild"
fi

NODE_ENV=production RAILS_ENV=production bundle exec rails server -p 3001
10 changes: 10 additions & 0 deletions react_on_rails/spec/dummy/bin/prod-assets
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

export NODE_ENV=production
export RAILS_ENV=production
if [ "$CI" = "true" ]; then
bundle exec bootsnap precompile --gemfile app/ lib/ config/
fi
pnpm run build:rescript
bundle exec rake react_on_rails:generate_packs
bundle exec rails assets:precompile
41 changes: 25 additions & 16 deletions react_on_rails/spec/dummy/config/puma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,45 @@
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count

rails_env = ENV.fetch("RAILS_ENV", "development")

# Specifies the `worker_timeout` threshold that Puma will use to wait before
# terminating a worker in development environments.
#
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
worker_timeout 3600 if rails_env == "development"

# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT", 3000)

# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV", "development")
environment rails_env

# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE", "tmp/pids/server.pid")

# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }

# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!
if rails_env == "production"
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
workers ENV.fetch("WEB_CONCURRENCY", 2)

# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
preload_app!

# Specifies the `worker_shutdown_timeout` threshold that Puma will use to wait before
# terminating a worker.
#
worker_shutdown_timeout 60
end

# Allow puma to be restarted by `bin/rails restart` command.
plugin :tmp_restart
3 changes: 0 additions & 3 deletions react_on_rails_pro/Gemfile.development_dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ gem "puma", "~> 6"
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem "jbuilder"

gem "pg"

# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem "turbolinks"
gem "sqlite3", "~> 1.4"
gem "uglifier"
gem "jquery-rails"
gem "sprockets"
gem "sass-rails"
Expand Down
5 changes: 0 additions & 5 deletions react_on_rails_pro/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ GEM
parser (3.3.3.0)
ast (~> 2.4.1)
racc
pg (1.5.6)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
Expand Down Expand Up @@ -434,8 +433,6 @@ GEM
turbolinks-source (5.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (2.5.0)
uri (1.0.3)
useragent (0.16.11)
Expand Down Expand Up @@ -488,7 +485,6 @@ DEPENDENCIES
net-http
net-imap
net-smtp
pg
pry (>= 0.14.1)
pry-byebug!
pry-doc
Expand All @@ -514,7 +510,6 @@ DEPENDENCIES
sprockets
sqlite3 (~> 1.4)
turbolinks
uglifier
web-console
webdrivers (= 5.3.0)
webmock
Expand Down
5 changes: 0 additions & 5 deletions react_on_rails_pro/spec/dummy/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,6 @@ GEM
parser (3.3.3.0)
ast (~> 2.4.1)
racc
pg (1.5.6)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
Expand Down Expand Up @@ -470,8 +469,6 @@ GEM
turbolinks-source (5.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (2.5.0)
uri (1.0.3)
useragent (0.16.11)
Expand Down Expand Up @@ -535,7 +532,6 @@ DEPENDENCIES
net-http
net-imap
net-smtp
pg
prism-rails
pry (>= 0.14.1)
pry-byebug!
Expand Down Expand Up @@ -563,7 +559,6 @@ DEPENDENCIES
sprockets
sqlite3 (~> 1.4)
turbolinks
uglifier
web-console
webdrivers (= 5.3.0)
webmock
Expand Down
6 changes: 6 additions & 0 deletions react_on_rails_pro/spec/dummy/Procfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Procfile for production mode (precompiled assets)

rails: RAILS_ENV=production NODE_ENV=production bin/rails s -p 3001

# Start Node server for server rendering.
node-renderer: NODE_ENV=production RENDERER_LOG_LEVEL=error RENDERER_PORT=3800 node client/node-renderer.js
40 changes: 40 additions & 0 deletions react_on_rails_pro/spec/dummy/bin/prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash

# Run only after ./prod-assets

# Check if assets are precompiled
MANIFEST="public/webpack/production/manifest.json"

if [ ! -d "public/assets" ]; then
echo "ERROR: public/assets not found. Run ./bin/prod-assets first"
exit 1
fi

if [ ! -f "$MANIFEST" ]; then
echo "ERROR: $MANIFEST not found. Run ./bin/prod-assets first"
exit 1
fi

# Simple up-to-date check: warn if source files are newer than manifest.json
if find client config -type f \( -name "*.[jt]s" -o -name "*.[jt]sx" \) -newer "$MANIFEST" 2>/dev/null | grep -q .; then
echo "WARNING: client or config has changes newer than compiled assets"
echo "Consider running ./bin/prod-assets to rebuild"
fi

if [ -f "yarn.lock" ] && [ "yarn.lock" -nt "$MANIFEST" ]; then
echo "WARNING: yarn.lock is newer than compiled assets"
echo "Consider running ./bin/prod-assets to rebuild"
fi

export NODE_ENV=production
export RAILS_ENV=production

if command -v overmind &> /dev/null; then
overmind start -f Procfile.prod
elif command -v foreman &> /dev/null; then
foreman start -f Procfile.prod
else
echo "Installing foreman..."
gem install foreman
foreman start -f Procfile.prod
fi
9 changes: 9 additions & 0 deletions react_on_rails_pro/spec/dummy/bin/prod-assets
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

export NODE_ENV=production
export RAILS_ENV=production
if [ "$CI" = "true" ]; then
bundle exec bootsnap precompile --gemfile app/ lib/ config/
fi
bundle exec rails react_on_rails:generate_packs
bundle exec rails assets:precompile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.

# Use a hardcoded secret for this test/dummy app (not for real production use)
config.secret_key_base = ENV.fetch("SECRET_KEY_BASE", "dummy-secret-key-base-for-testing-only")

# Code is not reloaded between requests.
config.cache_classes = true

Expand All @@ -19,8 +22,9 @@
config.public_file_server.enabled = true

# Compress JavaScripts and CSS.
config.assets.js_compressor = Uglifier.new(harmony: true)
config.assets.css_compressor = :csso
# JS/CSS compression handled by Webpack/Shakapacker, not needed for Sprockets
# config.assets.js_compressor = Uglifier.new(harmony: true)
# config.assets.css_compressor = :csso

# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
Expand Down
Loading
Loading