diff --git a/frameworks/Ruby/hanami/.env b/frameworks/Ruby/hanami/.env new file mode 100644 index 00000000000..c28bf215c1f --- /dev/null +++ b/frameworks/Ruby/hanami/.env @@ -0,0 +1,3 @@ +HANAMI_ENV=production +HANAMI_PORT=8080 +DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world diff --git a/frameworks/Ruby/hanami/Gemfile.lock b/frameworks/Ruby/hanami/Gemfile.lock new file mode 100644 index 00000000000..36b859fb018 --- /dev/null +++ b/frameworks/Ruby/hanami/Gemfile.lock @@ -0,0 +1,166 @@ +GEM + remote: https://rubygems.org/ + specs: + bigdecimal (3.1.9) + concurrent-ruby (1.3.4) + dry-auto_inject (1.1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-cli (1.2.0) + dry-configurable (1.3.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-core (1.1.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + dry-events (1.1.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + dry-files (1.1.0) + dry-inflector (1.2.0) + dry-initializer (3.2.0) + dry-logger (1.0.4) + dry-logic (1.6.0) + bigdecimal + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-monitor (1.0.1) + dry-configurable (~> 1.0, < 2) + dry-core (~> 1.0, < 2) + dry-events (~> 1.0, < 2) + dry-schema (1.13.4) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.4, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-struct (1.7.0) + dry-core (~> 1.1) + dry-types (~> 1.8) + ice_nine (~> 0.11) + zeitwerk (~> 2.6) + dry-system (1.2.0) + dry-auto_inject (~> 1.1) + dry-configurable (~> 1.3) + dry-core (~> 1.1) + dry-inflector (~> 1.1) + dry-transformer (1.0.1) + zeitwerk (~> 2.6) + dry-types (1.8.0) + bigdecimal (~> 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) + dry-validation (1.10.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-schema (>= 1.12, < 2) + zeitwerk (~> 2.6) + hanami (2.2.1) + bundler (>= 1.16, < 3) + dry-configurable (~> 1.0, >= 1.2.0, < 2) + dry-core (~> 1.0, < 2) + dry-inflector (~> 1.0, >= 1.1.0, < 2) + dry-logger (~> 1.0, < 2) + dry-monitor (~> 1.0, >= 1.0.1, < 2) + dry-system (~> 1.1) + hanami-cli (~> 2.2.1) + hanami-utils (~> 2.2) + json (>= 2.7.2) + zeitwerk (~> 2.6) + hanami-cli (2.2.1) + bundler (~> 2.1) + dry-cli (~> 1.0, >= 1.1.0) + dry-files (~> 1.0, >= 1.0.2, < 2) + dry-inflector (~> 1.0, < 2) + rake (~> 13.0) + zeitwerk (~> 2.6) + hanami-controller (2.1.0) + dry-configurable (~> 1.0, < 2) + dry-core (~> 1.0) + hanami-utils (~> 2.1) + rack (~> 2.0) + zeitwerk (~> 2.6) + hanami-router (2.1.0) + mustermann (~> 3.0) + mustermann-contrib (~> 3.0) + rack (~> 2.0) + hanami-utils (2.2.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-transformer (~> 1.0, < 2) + hanami-validations (2.1.0) + dry-validation (>= 1.10, < 2) + zeitwerk (~> 2.6.0) + hansi (0.2.1) + ice_nine (0.11.2) + json (2.9.1) + logger (1.6.4) + mustermann (3.0.3) + ruby2_keywords (~> 0.0.1) + mustermann-contrib (3.0.3) + hansi (~> 0.2.0) + mustermann (= 3.0.3) + nio4r (2.7.4) + pg (1.5.9) + puma (6.5.0) + nio4r (~> 2.0) + rack (2.2.9) + rake (13.2.1) + rom (5.3.2) + rom-changeset (~> 5.3, >= 5.3.0) + rom-core (~> 5.3, >= 5.3.2) + rom-repository (~> 5.3, >= 5.3.0) + rom-changeset (5.3.0) + dry-core (~> 1.0) + rom-core (~> 5.3) + transproc (~> 1.0, >= 1.1.0) + rom-core (5.3.2) + concurrent-ruby (~> 1.1) + dry-configurable (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-initializer (~> 3.0, >= 3.0.1) + dry-struct (~> 1.0) + dry-types (~> 1.6) + transproc (~> 1.0, >= 1.1.0) + rom-repository (5.3.0) + dry-core (~> 1.0) + dry-initializer (~> 3.0, >= 3.0.1) + rom-core (~> 5.3, >= 5.3.0) + rom-sql (3.6.5) + dry-core (~> 1.0) + dry-types (~> 1.0) + rom (~> 5.2, >= 5.2.1) + sequel (>= 4.49) + ruby2_keywords (0.0.5) + sequel (5.88.0) + bigdecimal + transproc (1.1.1) + zeitwerk (2.6.18) + +PLATFORMS + ruby + x86_64-darwin-23 + +DEPENDENCIES + dry-types (~> 1.0, >= 1.6.1) + hanami (~> 2.0) + hanami-controller (~> 2.0) + hanami-router (~> 2.0) + hanami-validations (~> 2.0) + pg + puma + rake + rom (~> 5.3) + rom-sql (~> 3.6) + +BUNDLED WITH + 2.5.16 diff --git a/frameworks/Ruby/hanami/app/actions/db/index.rb b/frameworks/Ruby/hanami/app/actions/db/index.rb index c32ec0f1df0..98b8ed970d8 100644 --- a/frameworks/Ruby/hanami/app/actions/db/index.rb +++ b/frameworks/Ruby/hanami/app/actions/db/index.rb @@ -8,7 +8,7 @@ class Index < HelloWorld::Action include Deps["persistence.rom"] def handle(*, response) - world = rom.relations[:World].where(id: random_id).one + world = rom.relations[:World].by_pk(random_id).one response.headers['Server'] = 'hanami' response.headers['Date'] = Time.now.httpdate response.format = :json diff --git a/frameworks/Ruby/hanami/app/actions/queries/index.rb b/frameworks/Ruby/hanami/app/actions/queries/index.rb new file mode 100644 index 00000000000..5a1d0bd1419 --- /dev/null +++ b/frameworks/Ruby/hanami/app/actions/queries/index.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module HelloWorld + module Actions + module Queries + class Index < HelloWorld::Action + QUERY_RANGE = 1..10_000 # range of IDs in the Fortune DB + ALL_IDS = QUERY_RANGE.to_a # enumeration of all the IDs in fortune DB + MIN_QUERIES = 1 # min number of records that can be retrieved + MAX_QUERIES = 500 # max number of records that can be retrieved + + include Deps["persistence.rom"] + + def handle(request, response) + worlds = ALL_IDS.sample(queries(request)).map do |id| + rom.relations[:World].by_pk(id).one + end + response.headers['Server'] = 'hanami' + response.headers['Date'] = Time.now.httpdate + response.format = :json + response.body = worlds.to_json + end + + private + + def queries(request) + request.params[:queries].to_i.clamp(MIN_QUERIES, MAX_QUERIES) + end + end + end + end +end diff --git a/frameworks/Ruby/hanami/app/actions/updates/index.rb b/frameworks/Ruby/hanami/app/actions/updates/index.rb new file mode 100644 index 00000000000..54f963f7bf2 --- /dev/null +++ b/frameworks/Ruby/hanami/app/actions/updates/index.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module HelloWorld + module Actions + module Updates + class Index < HelloWorld::Action + QUERY_RANGE = 1..10_000 # range of IDs in the Fortune DB + ALL_IDS = QUERY_RANGE.to_a # enumeration of all the IDs in fortune DB + MIN_QUERIES = 1 # min number of records that can be retrieved + MAX_QUERIES = 500 # max number of records that can be retrieved + + include Deps["persistence.rom"] + + def handle(request, response) + worlds = ALL_IDS.sample(queries(request)).map do |id| + world = rom.relations[:World].by_pk(id) + world_struct = world.one + new_value = random_id + new_value = random_id while new_value == world_struct[:randomnumber] + world_struct[:randomnumber] = new_value + world.command(:update).call(randomnumber: world_struct[:randomnumber]) + world_struct + end + response.headers['Server'] = 'hanami' + response.headers['Date'] = Time.now.httpdate + response.format = :json + response.body = worlds.to_json + end + + private + + def queries(request) + request.params[:queries].to_i.clamp(MIN_QUERIES, MAX_QUERIES) + end + + def random_id + Random.rand(QUERY_RANGE) + end + end + end + end +end diff --git a/frameworks/Ruby/hanami/benchmark_config.json b/frameworks/Ruby/hanami/benchmark_config.json index d5ee774c13f..d384577682c 100644 --- a/frameworks/Ruby/hanami/benchmark_config.json +++ b/frameworks/Ruby/hanami/benchmark_config.json @@ -2,8 +2,10 @@ "framework": "hanami", "tests": [{ "default": { - "db_url": "/db", "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", diff --git a/frameworks/Ruby/hanami/config/providers/persistence.rb b/frameworks/Ruby/hanami/config/providers/persistence.rb index 28234177e29..0aa12ececf6 100644 --- a/frameworks/Ruby/hanami/config/providers/persistence.rb +++ b/frameworks/Ruby/hanami/config/providers/persistence.rb @@ -5,12 +5,10 @@ require_relative '../auto_tune' num_workers, num_threads = auto_tune - opts = {} - - if (threads = num_threads) > 1 - opts[:max_connections] = (2 * Math.log(threads)).floor - opts[:pool_timeout] = 10 - end + opts = { + max_connections: 3, + pool_timeout: 10 + } config = ROM::Configuration.new(:sql, target["settings"].database_url, opts) register "config", config @@ -27,4 +25,8 @@ register "rom", ROM.container(config) end + + stop do + target["persistence.rom"].disconnect + end end diff --git a/frameworks/Ruby/hanami/config/puma.rb b/frameworks/Ruby/hanami/config/puma.rb index b360cf8a278..83e2dc90637 100644 --- a/frameworks/Ruby/hanami/config/puma.rb +++ b/frameworks/Ruby/hanami/config/puma.rb @@ -5,7 +5,7 @@ num_workers, num_threads = auto_tune workers num_workers -threads num_threads, num_threads +threads 3, 3 port ENV.fetch("HANAMI_PORT", 2300) environment ENV.fetch("HANAMI_ENV", "development") diff --git a/frameworks/Ruby/hanami/config/routes.rb b/frameworks/Ruby/hanami/config/routes.rb index 77ea9582b13..d568af27c70 100644 --- a/frameworks/Ruby/hanami/config/routes.rb +++ b/frameworks/Ruby/hanami/config/routes.rb @@ -4,6 +4,8 @@ module HelloWorld class Routes < Hanami::Routes get "/db", to: "db.index" get "/json", to: "json.index" + get "/updates", to: "updates.index" get "/plaintext", to: "plaintext.index" + get "/queries", to: "queries.index" end end diff --git a/frameworks/Ruby/hanami/hanami.dockerfile b/frameworks/Ruby/hanami/hanami.dockerfile index 6ba8e69f3e6..09892d3f9e7 100644 --- a/frameworks/Ruby/hanami/hanami.dockerfile +++ b/frameworks/Ruby/hanami/hanami.dockerfile @@ -7,15 +7,12 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 ENV LD_PRELOAD=libjemalloc.so.2 +ADD ./ /hanami WORKDIR /hanami -COPY Gemfile ./ - ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 -COPY . . - EXPOSE 8080 ENV HANAMI_ENV=production