{"id":17558141,"url":"https://github.com/fractaledmind/wrocloverb-2024","last_synced_at":"2026-03-02T18:37:30.095Z","repository":{"id":231337439,"uuid":"781525833","full_name":"fractaledmind/wrocloverb-2024","owner":"fractaledmind","description":"A demo SQLite on Rails application","archived":false,"fork":false,"pushed_at":"2024-05-01T11:23:54.000Z","size":223,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-05-01T13:28:26.348Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fractaledmind.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-03T14:48:59.000Z","updated_at":"2024-05-03T11:48:24.761Z","dependencies_parsed_at":"2024-05-03T11:48:19.294Z","dependency_job_id":"bcec6867-da96-49bc-b8f8-bdd3540de819","html_url":"https://github.com/fractaledmind/wrocloverb-2024","commit_stats":null,"previous_names":["fractaledmind/wrocloverb-2024"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fractaledmind%2Fwrocloverb-2024","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fractaledmind%2Fwrocloverb-2024/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fractaledmind%2Fwrocloverb-2024/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fractaledmind%2Fwrocloverb-2024/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fractaledmind","download_url":"https://codeload.github.com/fractaledmind/wrocloverb-2024/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240934412,"owners_count":19880991,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-21T09:43:21.940Z","updated_at":"2026-03-02T18:37:25.062Z","avatar_url":"https://github.com/fractaledmind.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# README\n\nThis is an app built for demonstration purposes for the [wroclove.rb conference](https://wrocloverb.com) held in Wrocław, Poland on April 12-14, 2024.\n\nIt is intended to be run locally in the `RAILS_ENV=production` environment to demonstrate the performance characteristics of a Rails application using SQLite.\n\n## Setup\n\nAfter cloning the repository, run the `bin/setup` command to install the dependencies and set up the database. It is recommended to run all commands in the `production` environments to allow you to better simulate the application locally:\n\n```sh\nRAILS_ENV=production bin/setup\n```\n\n## Details\n\nThis application runs on Ruby 3.2.1, Rails `main`, and SQLite 3.45.2 (gem version 1.7.3).\n\nIt was created using the following command:\n\n```sh\nrails new wrocloverb --main --database=sqlite3 --asset-pipeline=propshaft --javascript=esbuild --css=tailwind --skip-jbuilder --skip-action-mailbox --skip-spring\n```\n\nSo it uses [`propshaft`](https://github.com/rails/propshaft) for asset compilation, [`esbuild`](https://esbuild.github.io) for JavaScript bundling, and [`tailwind`](https://tailwindcss.com) for CSS.\n\nThe application is a basic \"Hacker News\" style app with `User`s, `Post`s, and `Comment`s. The seeds file will create ~100 users, ~1,000 posts, and ~10 comments per post. Every user has the same password: `password`, so you can sign in as any user to test the app.\n\n## Load Testing\n\nLoad testing can be done using the [`hey` CLI utility](https://github.com/rakyll/hey), which can be installed on MacOS via [homebrew](https://brew.sh):\n\n```sh\nbrew install hey\n```\n\nor using their [precompiled binaries](https://github.com/rakyll/hey?tab=readme-ov-file#installation) on other platforms.\n\nIn order to perform the load testing, you will need to run the web server in the `production` environment. To do this from your laptop, there are a few environment variables you will need to set:\n\n```sh\nRELAX_SSL=true RAILS_LOG_LEVEL=warn SECRET_KEY_BASE=asdf RAILS_ENV=production WEB_CONCURRENCY=10 RAILS_MAX_THREADS=3 bin/rails server\n```\n\nThe `RELAX_SSL` environment variable is necessary to allow you to use `http://localhost`. The `RAILS_LOG_LEVEL` is set to `warn` to reduce the amount of logging output. The `SECRET_KEY_BASE` is a dummy value that is required for the app to start. Set `WEB_CONCURRENCY` to the number of cores you have on your laptop. I am on an M1 Macbook Pro with 10 cores, and thus I set the value to 10. The `RAILS_MAX_THREADS` controls the number of threads per worker. I left it at the default of 3, but you can tweak it to see how it affects performance.\n\nWith your server running in one terminal window, you can use the load testing utility to test the app in another terminal window. Here is the shape of the command you will use to test the app:\n\n```sh\nhey -c N -z 10s -m POST http://127.0.0.1:3000/benchmarking/PATH\n```\n\n`N` is the number of concurrent requests that `hey` will make. I recommend running a large variety of different scenarios with different values of `N`. Personally, I scale up from 1 to 256 concurrent requests, doubling the number of concurrent requests each time. In general, when `N` matches your `WEB_CONCURRENCY` number, this is mostly likely the sweet spot for this app.\n\n`PATH` can be any of the benchmarking paths defined in the app. The app has a few different paths that you can test. From the `routes.rb` file:\n\n```ruby\nnamespace :benchmarking do\n  post \"read_heavy\"\n  post \"write_heavy\"\n  post \"balanced\"\n  post \"post_create\"\n  post \"comment_create\"\n  post \"post_destroy\"\n  post \"comment_destroy\"\n  post \"post_show\"\n  post \"posts_index\"\n  post \"user_show\"\nend\n```\n\nThe `read_heavy`, `write_heavy`, and `balanced` paths are designed to test the performance of the app under a mix of scenarios. Each of those paths will randomly run one of the more precise actions, with the overall distribution defined in the controller to match the name. The rest of the paths are specific actions, which you can use if you want to see how a particular action handles concurrent load.\n\nIn general, I recommend running the `balanced` path with a variety of different values of `N` to see how the app performs under a variety of different scenarios.\n\nFor load testing the app in our different configurations, we will run the `balanced` benchmark with 20 concurrent requests (twice the number of Puma workers we spin up, to ensure contention) for 10 seconds:\n\n```sh\nhey -c 20 -z 10s -m POST http://127.0.0.1:3000/benchmarking/balanced\n```\n\n## Results\n\nRunning this load test against our app, I get the following results on my laptop:\n\n```\n$ hey -c 20 -z 10s -m POST http://127.0.0.1:3000/benchmarking/balanced\n\nSummary:\n  Total:\t16.2924 secs\n  Slowest:\t10.5007 secs\n  Fastest:\t0.0028 secs\n  Average:\t0.6316 secs\n  Requests/sec:\t23.5079\n\n  Total data:\t9093582 bytes\n  Size/request:\t23743 bytes\n\nResponse time histogram:\n  0.003 [1]\t|\n  1.053 [342]\t|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n  2.102 [0]\t|\n  3.152 [0]\t|\n  4.202 [0]\t|\n  5.252 [11]\t|■\n  6.302 [25]\t|■■■\n  7.351 [0]\t|\n  8.401 [0]\t|\n  9.451 [0]\t|\n  10.501 [4]\t|\n\n\nLatency distribution:\n  10% in 0.0091 secs\n  25% in 0.0143 secs\n  50% in 0.0264 secs\n  75% in 0.0497 secs\n  90% in 5.2219 secs\n  95% in 5.2669 secs\n  99% in 10.4778 secs\n\nDetails (average, fastest, slowest):\n  DNS+dialup:\t0.0000 secs, 0.0028 secs, 10.5007 secs\n  DNS-lookup:\t0.0000 secs, 0.0000 secs, 0.0000 secs\n  req write:\t0.0000 secs, 0.0000 secs, 0.0003 secs\n  resp wait:\t0.5302 secs, 0.0028 secs, 10.5006 secs\n  resp read:\t0.0001 secs, 0.0000 secs, 0.0015 secs\n\nStatus code distribution:\n  [200]\t320 responses\n  [500]\t63 responses\n```\n\nThese results are from the run with the highest requets per second. I ran the command three times on a freshly seeded database (not resetting the database after each run, only at the beginning of the set of three runs). Across the three runs, the single slowest request took 15.7031 seconds. The average request time was 1.1122 seconds (`[1.1525, 0.6316, 1.5525]`). The average requests per second was 16.4845 (`[13.1033, 23.5079, 12.8424]`). On average, there were 40.67 errored responses per run (`[34, 63, 25]`). Finally, the average 90th percentile response time was 6,97336667 seconds (`[5.2493, 5.2219, 10.4489]`).\n\nThere are a few key details to pay attention to in the output:\n\n1. Nearly 10% of the requests recieve an error response. Looking at the logs, you will see that all of these errors are `SQLite3::BusyException: database is locked` exceptions.\n2. The slowest request took 14\u0026times; longer than the average request. This is a sign that the app is not handling the load well.\n3. Even on our high-powered laptop over localhost, our server can only support 16 requests per second. This is a very low number, and it is likely that the app will not be able to handle even a small number of users in production.\n4. The p90 response time is nearly 7 seconds. This is a very high number, and it is likely that users will not be happy with the performance of the app.\n\nThe goal of our work is to improve these metrics while simultaneously adding more features to the app.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffractaledmind%2Fwrocloverb-2024","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffractaledmind%2Fwrocloverb-2024","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffractaledmind%2Fwrocloverb-2024/lists"}