Browse Source

[Ruby] Add rage-rb (#8908)

Roman Samoilov 1 year ago
parent
commit
6837c80997

+ 13 - 0
frameworks/Ruby/rage/Gemfile

@@ -0,0 +1,13 @@
+source "https://rubygems.org"
+
+gem "rage-rb", "~> 1.3"
+
+gem "pg", "~> 1.0"
+gem "activerecord", "~> 7.0.0", require: "active_record"
+
+# Build JSON APIs with ease
+# gem "alba"
+
+# Get 50% to 150% boost when parsing JSON.
+# Rage will automatically use FastJsonparser if it is available.
+# gem "fast_jsonparser"

+ 47 - 0
frameworks/Ruby/rage/README.md

@@ -0,0 +1,47 @@
+# Rage Benchmarking Test
+
+Rage is a fast web framework compatible with Rails. It uses an event-driven architecture and implements a lightweight, cooperative concurrency model based on Ruby Fibers.
+
+https://github.com/rage-rb/rage
+
+### Test Type Implementation Source Code
+
+* [JSON](app/controllers/benchmarks_controller.rb)
+* [PLAINTEXT](app/controllers/benchmarks_controller.rb)
+* [DB](app/controllers/benchmarks_controller.rb)
+* [QUERY](app/controllers/benchmarks_controller.rb)
+* [UPDATE](app/controllers/benchmarks_controller.rb)
+* [FORTUNES](app/controllers/benchmarks_controller.rb)
+
+## Important Libraries
+
+The tests were run with:
+
+* [ActiveRecord](https://rubygems.org/gems/activerecord)
+* [PG](https://rubygems.org/gems/pg)
+
+## Test URLs
+
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+### DB
+
+http://localhost:8080/db
+
+### QUERY
+
+http://localhost:8080/queries?queries=
+
+### UPDATE
+
+http://localhost:8080/updates?queries=
+
+### FORTUNES
+
+http://localhost:8080/fortunes

+ 1 - 0
frameworks/Ruby/rage/Rakefile

@@ -0,0 +1 @@
+require_relative "config/application"

+ 2 - 0
frameworks/Ruby/rage/app/controllers/application_controller.rb

@@ -0,0 +1,2 @@
+class ApplicationController < RageController::API
+end

+ 77 - 0
frameworks/Ruby/rage/app/controllers/benchmarks_controller.rb

@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+class BenchmarksController < ApplicationController
+  ALL_DB_IDS = (1..10_000).to_a
+  FORTUNES_TEMPLATE = ERB.new(Rage.root.join("app/views/fortunes.html.erb").read)
+
+  before_action do
+    headers["server"] = "rage"
+  end
+
+  def json
+    render json: { message: "Hello, World!" }
+  end
+
+  def plaintext
+    render plain: "Hello, World!"
+  end
+
+  def db
+    render json: World.find(random_id)
+  end
+
+  def queries
+    records = requested_ids.map do |id|
+      World.find(id)
+    end
+
+    render json: records
+  end
+
+  def fortunes
+    records = Fortune.pluck(:id, :message).map! { |id, message| { id:, message: } }
+
+    records << Fortune.new(id: 0, message: "Additional fortune added at request time.")
+    records.sort_by! { |record| record[:message] }
+
+    render plain: FORTUNES_TEMPLATE.result(binding)
+    headers["content-type"] = "text/html; charset=utf-8"
+  end
+
+  def updates
+    records = requested_ids.map do |id|
+      World.find(id)
+    end
+
+    updates = records.map do |record|
+      new_value = random_id
+      new_value = random_id until new_value != record.randomNumber
+
+      record.randomNumber = new_value
+
+      { id: record.id, randomnumber: new_value }
+    end
+
+    World.upsert_all(updates.sort_by! { |u| u[:id] })
+
+    render json: records
+  end
+
+  private
+
+  def requested_ids
+    num = params[:queries].to_i
+
+    if num > 500
+      num = 500
+    elsif num < 1
+      num = 1
+    end
+
+    ALL_DB_IDS.sample(num)
+  end
+
+  def random_id
+    Random.rand(9_999) + 1
+  end
+end

+ 3 - 0
frameworks/Ruby/rage/app/models/application_record.rb

@@ -0,0 +1,3 @@
+class ApplicationRecord < ActiveRecord::Base
+  primary_abstract_class
+end

+ 7 - 0
frameworks/Ruby/rage/app/models/fortune.rb

@@ -0,0 +1,7 @@
+class Fortune < ApplicationRecord
+  self.table_name = "Fortune"
+
+  def as_json(*)
+    attributes
+  end
+end

+ 9 - 0
frameworks/Ruby/rage/app/models/world.rb

@@ -0,0 +1,9 @@
+class World < ApplicationRecord
+  self.table_name = "World"
+
+  def as_json(*)
+    attributes
+  end
+
+  alias_attribute(:randomNumber, :randomnumber)
+end

+ 12 - 0
frameworks/Ruby/rage/app/views/fortunes.html.erb

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head><title>Fortunes</title></head>
+  <body>
+    <table>
+    <tr><th>id</th><th>message</th></tr>
+    <% records.each do |record| %>
+      <tr><td><%= record[:id] %></td><td><%= CGI.escape_html(record[:message]) %></td></tr>
+    <% end %>
+    </table>
+  </body>
+</html>

+ 30 - 0
frameworks/Ruby/rage/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+  "framework": "rage",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "postgres",
+        "framework": "Rage",
+        "language": "Ruby",
+        "flavor": "None",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Rage-Iodine",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Rage",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 4 - 0
frameworks/Ruby/rage/config.ru

@@ -0,0 +1,4 @@
+require_relative "config/application"
+
+run Rage.application
+Rage.load_middlewares(self)

+ 14 - 0
frameworks/Ruby/rage/config/application.rb

@@ -0,0 +1,14 @@
+require "bundler/setup"
+require "rage"
+Bundler.require(*Rage.groups)
+
+require "rage/all"
+
+Rage.configure do
+  # use this to add settings that are constant across all environments
+end
+
+require "erb"
+require "cgi"
+
+require "rage/setup"

+ 4 - 0
frameworks/Ruby/rage/config/environments/development.rb

@@ -0,0 +1,4 @@
+Rage.configure do
+  config.server.workers_count = -1
+  config.logger = ActiveRecord::Base.logger = Rage::Logger.new(STDOUT)
+end

+ 3 - 0
frameworks/Ruby/rage/config/environments/production.rb

@@ -0,0 +1,3 @@
+Rage.configure do
+  config.logger = nil
+end

+ 17 - 0
frameworks/Ruby/rage/config/initializers/activerecord.rb

@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require "etc"
+
+connection = {
+  adapter: "postgresql",
+  host: "tfb-database",
+  username: "benchmarkdbuser",
+  password: "benchmarkdbpass",
+  database: "hello_world",
+  reaping_frequency: 0,
+  pool: (2 * Math.log(256 / Etc.nprocessors)).floor
+}
+
+puts "ActiveRecord connection options: #{connection.inspect}"
+
+ActiveRecord::Base.establish_connection(connection)

+ 10 - 0
frameworks/Ruby/rage/config/routes.rb

@@ -0,0 +1,10 @@
+Rage.routes.draw do
+  root to: ->(env) { [200, {}, "It works!"] }
+
+  get "json", to: "benchmarks#json"
+  get "plaintext", to: "benchmarks#plaintext"
+  get "db", to: "benchmarks#db"
+  get "queries", to: "benchmarks#queries"
+  get "fortunes", to: "benchmarks#fortunes"
+  get "updates", to: "benchmarks#updates"
+end

+ 0 - 0
frameworks/Ruby/rage/lib/.keep


+ 14 - 0
frameworks/Ruby/rage/rage.dockerfile

@@ -0,0 +1,14 @@
+FROM ruby:3.3
+
+EXPOSE 8080
+WORKDIR /rage
+
+COPY Gemfile*  /rage/
+RUN bundle install --jobs=8
+COPY . /rage
+
+ENV RUBY_YJIT_ENABLE=1
+ENV RAGE_PATCH_AR_POOL=1
+ENV BUNDLE_FORCE_RUBY_PLATFORM=true
+
+CMD bundle exec rage s -b 0.0.0.0 -p 8080 -e production