diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 571389a3..6550566f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,22 +10,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 - services: - postgres: - image: postgres:17-alpine - ports: ['5432:5432'] - env: - POSTGRES_PASSWORD: postgres - - redis: - image: redis:alpine - ports: ['6379:6379'] - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASSWORD: postgres - REDIS_URL: redis://localhost:6379/0 RAILS_ENV: test CI: true RUBY_YJIT_ENABLE: 1 @@ -56,7 +41,7 @@ jobs: - name: Check for TypeScript errors run: bin/yarn tsc - - name: Setup PostgreSQL + - name: Setup Database run: bin/rails db:create - name: Compile assets diff --git a/.rubocop.yml b/.rubocop.yml index 29d9da9d..7c7ae2d8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -13,6 +13,9 @@ AllCops: - bin/**/* - coverage/**/* - db/schema.rb + - db/cable_schema.rb + - db/cache_schema.rb + - db/queue_schema.rb - db/migrate/**/* - log/**/* - node_modules/**/* diff --git a/Brewfile b/Brewfile index ce6df78d..9cce109f 100644 --- a/Brewfile +++ b/Brewfile @@ -1,4 +1,2 @@ brew 'puma/puma/puma-dev' -brew 'postgresql@17' -brew 'redis' brew 'overmind' diff --git a/Gemfile b/Gemfile index c95e40ca..ba720f03 100644 --- a/Gemfile +++ b/Gemfile @@ -20,21 +20,27 @@ gem 'phlex-rails' # Heroicons extension for Phlex (https://github.com/nejdetkadir/phlex-heroicons) gem 'phlex-heroicons', github: 'nejdetkadir/phlex-heroicons' -# Pg is the Ruby interface to the PostgreSQL RDBMS (https://github.com/ged/ruby-pg) -gem 'pg', '~> 1.1' +# Ruby library to interface with the SQLite3 database engine (http://www.sqlite.org). (https://github.com/sparklemotion/sqlite3-ruby) +gem 'sqlite3', '>= 2.1' -# Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for Ruby/Rack applications (https://puma.io) +# A Ruby/Rack web server built for parallelism. (https://puma.io) gem 'puma', '>= 5.0' +# A database backed ActiveSupport::Cache::Store (http://github.com/rails/solid_cache) +gem 'solid_cache' + +# Database-backed Active Job backend. (https://github.com/rails/solid_queue) +gem 'solid_queue' + +# Database-backed Action Cable backend. (https://github.com/rails/solid_cable) +gem 'solid_cable' + # Boot large ruby/rails apps faster (https://github.com/Shopify/bootsnap) gem 'bootsnap', '>= 1.4.4', require: false # Timezone Data for TZInfo (https://tzinfo.github.io) gem 'tzinfo-data', platforms: %i[windows jruby] -# A Ruby client library for Redis (https://github.com/redis/redis-rb) -gem 'redis', '>= 4.0.1' - # Tame Rails' multi-line logging into a single line per request (https://github.com/roidrage/lograge) gem 'lograge' @@ -47,9 +53,6 @@ gem 'rack-canonical-host' # Brotli compression for Rack responses (http://github.com/marcotc/rack-brotli/) gem 'rack-brotli' -# Simple, efficient background processing for Ruby (https://sidekiq.org) -gem 'sidekiq' - # Lock staging servers from search engines and prying eyes. (http://lockup.interdiscipline.com) gem 'lockup', github: 'interdiscipline/lockup' diff --git a/Gemfile.lock b/Gemfile.lock index 6a7b3a9b..955f9d22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -125,6 +125,8 @@ GEM drb (2.2.1) dry-cli (1.2.0) erubi (1.13.1) + et-orbi (1.2.11) + tzinfo factory_bot (6.5.0) activesupport (>= 5.0.0) factory_bot_rails (6.4.4) @@ -134,6 +136,9 @@ GEM ffi (1.17.1-x86_64-linux-gnu) ffi (1.17.1-x86_64-linux-musl) formatador (1.1.0) + fugit (1.11.1) + et-orbi (~> 1, >= 1.2.11) + raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) guard (2.19.1) @@ -226,7 +231,6 @@ GEM parser (3.3.7.0) ast (~> 2.4.1) racc - pg (1.5.9) phlex (1.11.0) phlex-rails (1.2.2) phlex (>= 1.10, < 2) @@ -240,6 +244,7 @@ GEM public_suffix (6.0.1) puma (6.5.0) nio4r (~> 2.0) + raabro (1.4.0) racc (1.8.1) rack (3.1.8) rack-brotli (2.0.0) @@ -296,10 +301,6 @@ GEM rdoc (6.11.0) psych (>= 4.0.0) redcarpet (3.6.0) - redis (5.3.0) - redis-client (>= 0.22.0) - redis-client (0.23.2) - connection_pool regexp_parser (2.10.0) reline (0.6.0) io-console (~> 0.5) @@ -361,18 +362,31 @@ GEM ruby-progressbar (1.13.0) securerandom (0.4.1) shellany (0.0.1) - sidekiq (7.3.8) - base64 - connection_pool (>= 2.3.0) - logger - rack (>= 2.2.4) - redis-client (>= 0.22.2) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) + solid_cable (3.0.5) + actioncable (>= 7.2) + activejob (>= 7.2) + activerecord (>= 7.2) + railties (>= 7.2) + solid_cache (1.0.6) + activejob (>= 7.2) + activerecord (>= 7.2) + railties (>= 7.2) + solid_queue (1.1.2) + activejob (>= 7.1) + activerecord (>= 7.1) + concurrent-ruby (>= 1.3.1) + fugit (~> 1.11.0) + railties (>= 7.1) + thor (~> 1.3.1) + sqlite3 (2.5.0-arm64-darwin) + sqlite3 (2.5.0-x86_64-linux-gnu) + sqlite3 (2.5.0-x86_64-linux-musl) stimulus-rails (1.3.4) railties (>= 6.0.0) stringio (3.1.2) @@ -436,7 +450,6 @@ DEPENDENCIES lograge lookbook ostruct - pg (~> 1.1) phlex-heroicons! phlex-rails puma (>= 5.0) @@ -444,7 +457,6 @@ DEPENDENCIES rack-canonical-host rack-cors rails (~> 8.0.0) - redis (>= 4.0.1) rexml rorvswild rspec-rails @@ -455,8 +467,11 @@ DEPENDENCIES rubocop-rails rubocop-rspec rubocop-rspec_rails - sidekiq simplecov + solid_cable + solid_cache + solid_queue + sqlite3 (>= 2.1) stimulus-rails turbo-rails tzinfo-data diff --git a/README.md b/README.md index 8450f9b0..6d4ceb1e 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,8 @@ There are two sister repositories: - [Ruby](https://www.ruby-lang.org/de/) 3.4 - [Ruby on Rails](https://rubyonrails.org/) 8.0 - [ActionCable](https://guides.rubyonrails.org/action_cable_overview.html) for WebSocket communication -- [PostgreSQL](https://www.postgresql.org/) for using as SQL database -- [Sidekiq](https://sidekiq.org/) for background processing -- [Redis](https://redis.io/) for Caching, ActionCable, and Sidekiq +- [SQLite](https://www.sqlite.org/) for using as SQL database +- [SolideQueue](https://github.com/rails/solid_queue) for background processing ### Frontend @@ -175,7 +174,7 @@ git clone git@github.com:templatus/templatus-hotwire.git cd templatus-hotwire ``` -2. Install PostgreSQL, Redis, and puma-dev (if not already present). On a Mac with HomeBrew, run this to install from the `Brewfile`: +2. Install puma-dev (if not already present). On a Mac with HomeBrew, run this to install from the `Brewfile`: ```bash brew bundle diff --git a/app/controllers/cypress/cleanup_controller.rb b/app/controllers/cypress/cleanup_controller.rb index d63bd473..07e0acb2 100644 --- a/app/controllers/cypress/cleanup_controller.rb +++ b/app/controllers/cypress/cleanup_controller.rb @@ -9,9 +9,7 @@ def destroy tables.delete 'schema_migrations' tables.each do |table| sanitized_table = ActiveRecord::Base.connection.quote_table_name(table) - ActiveRecord::Base.connection.execute( - "TRUNCATE #{sanitized_table} CASCADE", - ) + ActiveRecord::Base.connection.execute("DELETE FROM #{sanitized_table}") end head :ok diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 024db686..d394c3d1 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,7 +1,7 @@ class ApplicationJob < ActiveJob::Base # Automatically retry jobs that encountered a deadlock # retry_on ActiveRecord::Deadlocked - # + # Most jobs are safe to ignore if the underlying records are no longer available # discard_on ActiveJob::DeserializationError end diff --git a/app/models/click.rb b/app/models/click.rb index 90161990..a0835740 100644 --- a/app/models/click.rb +++ b/app/models/click.rb @@ -2,8 +2,8 @@ # # Table name: clicks # -# id :bigint not null, primary key -# ip :inet not null +# id :integer not null, primary key +# ip :string not null # user_agent :string not null # created_at :datetime not null # diff --git a/app/views/components/about_component.rb b/app/views/components/about_component.rb index f400a19b..90084160 100644 --- a/app/views/components/about_component.rb +++ b/app/views/components/about_component.rb @@ -54,26 +54,10 @@ def feature(item) dd(class: 'mt-2 text-base text-gray-600 ml-9') do plain item[:description] - - sidekiq_link if item[:gem] == 'sidekiq' end end end - def sidekiq_link - p(class: 'mt-2 text-xs') do - plain ' → ' - - a( - href: sidekiq_web_path, - class: 'font-medium uppercase hover:underline', - data: { - turbo: false, - }, - ) { 'Admin frontend' } - end - end - FEATURES = [ { name: 'The backend', @@ -93,10 +77,10 @@ def sidekiq_link 'Rails is a web application development framework written in the Ruby programming language. It is designed to make programming web applications easier by making assumptions about what every developer needs to get started.', }, { - name: 'PostgreSQL', - href: 'https://www.postgresql.org/', + name: 'SQLite', + href: 'https://www.sqlite.org/', description: - 'PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.', + 'SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. SQLite is the most used database engine in the world. ', }, { name: 'Puma', @@ -105,18 +89,6 @@ def sidekiq_link description: 'Puma is a simple, fast, multi-threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications.', }, - { - name: 'Redis', - href: 'https://redis.io/', - description: - 'Redis is an open source, in-memory data structure store, used as a database, cache, and message broker.', - }, - { - name: 'Sidekiq', - gem: 'sidekiq', - href: 'https://sidekiq.org/', - description: 'Simple, efficient background processing for Ruby', - }, ], }, { @@ -251,14 +223,6 @@ def alpine_version # :nocov: end - def postgres_version - ActiveRecord::Base.connection.select_value('SHOW server_version;') - end - - def redis_version - Redis.new.info['redis_version'] - end - def ruby_version RUBY_VERSION end @@ -272,12 +236,7 @@ def external_version(name) Rails .cache .fetch('versions', expires_in: 1.hour) do - { - 'Alpine Linux' => alpine_version, - 'PostgreSQL' => postgres_version, - 'Redis' => redis_version, - 'Ruby' => ruby_version, - } + { 'Alpine Linux' => alpine_version, 'Ruby' => ruby_version } end @external_version[name] diff --git a/bin/jobs b/bin/jobs new file mode 100755 index 00000000..df2fa9b7 --- /dev/null +++ b/bin/jobs @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +require_relative '../config/environment' +require 'solid_queue/cli' + +SolidQueue::Cli.start(ARGV) diff --git a/compose.yml b/compose.yml index 7b49968a..756921c9 100644 --- a/compose.yml +++ b/compose.yml @@ -2,70 +2,20 @@ version: '3.9' x-app-base: &app_base build: . - links: - - db - - redis environment: &app_environment APP_HOST: localhost ASSET_HOST: null FORCE_SSL: 'false' - DB_HOST: db - DB_PASSWORD: my-secret-database-password - DB_USER: postgres SECRET_KEY_BASE: something-long-and-secret HONEYBADGER_API_KEY: null PLAUSIBLE_URL: null LOCKUP_CODEWORD: null services: - db: - environment: - POSTGRES_PASSWORD: my-secret-database-password - networks: - - internal - image: postgres:17-alpine - healthcheck: - test: ['CMD-SHELL', 'pg_isready -U postgres'] - volumes: - - postgresql:/var/lib/postgresql/data - - redis: - networks: - - internal - image: redis:7-alpine - healthcheck: - test: ['CMD', 'redis-cli', 'ping'] - volumes: - - redis:/data - - worker: - <<: *app_base - environment: - <<: *app_environment - REDIS_URL: redis://redis:6379/2 - networks: - - internal - command: bundle exec sidekiq - healthcheck: - test: 'ps ax | grep -v grep | grep sidekiq' - - cable: - <<: *app_base - environment: - <<: *app_environment - REDIS_URL: redis://redis:6379/1 - command: bundle exec puma -p 28080 cable/config.ru - healthcheck: - test: ['CMD-SHELL', 'nc -z 127.0.0.1 28080 || exit 1'] - networks: - - public - - internal - app: <<: *app_base environment: <<: *app_environment - REDIS_URL: redis://redis:6379/0 ports: - 3000 healthcheck: @@ -74,10 +24,6 @@ services: - public - internal -volumes: - postgresql: - redis: - networks: public: external: true diff --git a/config/cable.yml b/config/cable.yml index e6ac95e1..b9adc5aa 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,3 +1,7 @@ +# Async adapter only works within the same process, so for manually triggering cable updates from a console, +# and seeing results in the browser, you must do so from the web console (running inside the dev process), +# not a terminal started via bin/rails console! Add "console" to any action or any ERB template view +# to make the web console appear. development: adapter: async @@ -5,6 +9,9 @@ test: adapter: test production: - adapter: redis - url: <%= ENV.fetch('REDIS_URL', 'redis://localhost:6379/1') %> - channel_prefix: templatus_production + adapter: solid_cable + connects_to: + database: + writing: cable + polling_interval: 0.1.seconds + message_retention: 1.day diff --git a/config/cache.yml b/config/cache.yml new file mode 100644 index 00000000..19d49084 --- /dev/null +++ b/config/cache.yml @@ -0,0 +1,16 @@ +default: &default + store_options: + # Cap age of oldest cache entry to fulfill retention policies + # max_age: <%= 60.days.to_i %> + max_size: <%= 256.megabytes %> + namespace: <%= Rails.env %> + +development: + <<: *default + +test: + <<: *default + +production: + database: cache + <<: *default diff --git a/config/database.yml b/config/database.yml index adb34420..120aab1f 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,85 +1,40 @@ -# PostgreSQL. Versions 9.3 and up are supported. +# SQLite. Versions 3.8.0 and up are supported. +# gem install sqlite3 # -# Install the pg driver: -# gem install pg -# On macOS with Homebrew: -# gem install pg -- --with-pg-config=/usr/local/bin/pg_config -# On macOS with MacPorts: -# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config -# On Windows: -# gem install pg -# Choose the win32 build. -# Install PostgreSQL and put its /bin directory on your path. -# -# Configure Using Gemfile -# gem 'pg' +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem "sqlite3" # default: &default - adapter: postgresql - encoding: unicode - # For details on connection pooling, see Rails configuration guide - # https://guides.rubyonrails.org/configuring.html#database-pooling + adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> - - # The specified database role being used to connect to postgres. - # To create additional roles in postgres see `$ createuser --help`. - # When left blank, postgres will use the default role. This is - # the same name as the operating system user running Rails. - username: <%= ENV['DB_USER'] %> - - # The password associated with the postgres role (username). - password: <%= ENV['DB_PASSWORD'] %> - - # Connect on a TCP socket. Omitted by default since the client uses a - # domain socket that doesn't need configuration. Windows does not have - # domain sockets, so uncomment these lines. - host: <%= ENV['DB_HOST'] %> - - # The TCP port the server listens on. Defaults to 5432. - # If your server runs on a different port number, change accordingly. - #port: 5432 - - # Schema search path. The server defaults to $user,public - #schema_search_path: myapp,sharedapp,public - - # Minimum log levels, in increasing order: - # debug5, debug4, debug3, debug2, debug1, - # log, notice, warning, error, fatal, and panic - # Defaults to warning. - #min_messages: notice + timeout: 5000 development: <<: *default - # Use test database in Cypress mode. This allows writing Cypress tests without having to restart the server - database: "<%= Rails.configuration.x.cypress ? 'templatus-hotwire_test' : 'templatus-hotwire_development' %>" + database: storage/development.sqlite3 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default - database: templatus-hotwire_test + database: storage/test.sqlite3 -# As with config/credentials.yml, you never want to store sensitive information, -# like your database password, in your source code. If your source code is -# ever seen by anyone, they now have access to your database. -# -# Instead, provide the password or a full connection URL as an environment -# variable when you boot the app. For example: -# -# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" -# -# If the connection URL is provided in the special DATABASE_URL environment -# variable, Rails will automatically merge its configuration values on top of -# the values provided in this file. Alternatively, you can specify a connection -# URL environment variable explicitly: -# -# production: -# url: <%= ENV['MY_APP_DATABASE_URL'] %> -# -# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database -# for a full overview on how database connection configuration can be specified. -# +# Store production database in the storage/ directory, which by default +# is mounted as a persistent Docker volume in config/deploy.yml. production: - <<: *default - database: templatus-hotwire_production + primary: + <<: *default + database: storage/production.sqlite3 + cache: + <<: *default + database: storage/production_cache.sqlite3 + migrations_paths: db/cache_migrate + queue: + <<: *default + database: storage/production_queue.sqlite3 + migrations_paths: db/queue_migrate + cable: + <<: *default + database: storage/production_cable.sqlite3 + migrations_paths: db/cable_migrate diff --git a/config/environments/production.rb b/config/environments/production.rb index 37d9d7f3..57a62736 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -17,40 +17,31 @@ # Cache assets for far-future expiry since they are all digest stamped. config.public_file_server.headers = { - 'X-Content-Type-Options' => 'nosniff', - 'cache-control' => 'public, s-maxage=31536000, max-age=31536000, immutable', + 'cache-control' => "public, max-age=#{Integer(1.year, 10)}", } # Enable serving of images, stylesheets, and JavaScripts from an asset server. - config.asset_host = ENV.fetch('ASSET_HOST', nil).presence + # config.asset_host = "http://assets.example.com" # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Assume all access to the app is happening through a SSL-terminating reverse proxy. - config.assume_ssl = - ActiveModel::Type::Boolean.new.cast ENV.fetch('FORCE_SSL', true) + config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = - ActiveModel::Type::Boolean.new.cast ENV.fetch('FORCE_SSL', true) + config.force_ssl = true # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } - # Log to STDOUT with the current IP and request id as a default log tag. - config.log_tags = %i[remote_ip request_id] + # Log to STDOUT with the current request id as a default log tag. + config.log_tags = [:request_id] config.logger = ActiveSupport::TaggedLogging.logger($stdout) # Change to "debug" to log everything (including potentially personally-identifiable information!) config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info') - # Use lograge gem - config.lograge.enabled = true - config.lograge.custom_payload do |controller| - { user_agent: controller.request.user_agent } - end - # Prevent health checks from clogging up the logs. config.silence_healthcheck_path = '/up' @@ -58,12 +49,11 @@ config.active_support.report_deprecations = false # Replace the default in-process memory cache store with a durable alternative. - config.cache_store = - :redis_cache_store, - { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') } + config.cache_store = :solid_cache_store # Replace the default in-process and non-durable queuing backend for Active Job. - config.active_job.queue_adapter = :sidekiq + config.active_job.queue_adapter = :solid_queue + config.solid_queue.connects_to = { database: { writing: :queue } } # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. @@ -88,9 +78,6 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false - # Enable load_async - config.active_record.async_query_executor = :global_thread_pool - # Only use :id for inspections in production. config.active_record.attributes_for_inspect = [:id] @@ -99,9 +86,7 @@ # "example.com", # Allow requests from example.com # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` # ] - config.hosts = [ENV.fetch('APP_HOST', nil)] - # # Skip DNS rebinding protection for the default health check endpoint. - config.host_authorization = { exclude: ->(request) { request.path == '/up' } } + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb deleted file mode 100644 index 453b3f5e..00000000 --- a/config/initializers/sidekiq.rb +++ /dev/null @@ -1,7 +0,0 @@ -Sidekiq.configure_client do |config| - config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/2') } -end - -Sidekiq.configure_server do |config| - config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/2') } -end diff --git a/config/puma.rb b/config/puma.rb index 7abfdbdb..6899c5a2 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -33,6 +33,9 @@ # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart +# Run the Solid Queue supervisor inside of Puma for single-server deployments +plugin :solid_queue if ENV['SOLID_QUEUE_IN_PUMA'] + # Specify the PID file. Defaults to tmp/pids/server.pid in development. # In other environments, only set the PID file if requested. pidfile ENV['PIDFILE'] if ENV['PIDFILE'] diff --git a/config/queue.yml b/config/queue.yml new file mode 100644 index 00000000..9eace59c --- /dev/null +++ b/config/queue.yml @@ -0,0 +1,18 @@ +default: &default + dispatchers: + - polling_interval: 1 + batch_size: 500 + workers: + - queues: "*" + threads: 3 + processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %> + polling_interval: 0.1 + +development: + <<: *default + +test: + <<: *default + +production: + <<: *default diff --git a/config/recurring.yml b/config/recurring.yml new file mode 100644 index 00000000..d045b191 --- /dev/null +++ b/config/recurring.yml @@ -0,0 +1,10 @@ +# production: +# periodic_cleanup: +# class: CleanSoftDeletedRecordsJob +# queue: background +# args: [ 1000, { batch_size: 500 } ] +# schedule: every hour +# periodic_command: +# command: "SoftDeletedRecord.due.delete_all" +# priority: 2 +# schedule: at 5am every day diff --git a/config/routes.rb b/config/routes.rb index 052c1dc9..7aa2ad9f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,6 @@ # # Prefix Verb URI Pattern Controller#Action # rails_health_check GET /up(.:format) rails/health#show -# sidekiq_web /sidekiq Sidekiq::Web # lookbook /lookbook Lookbook::Engine # clicks GET /clicks(.:format) clicks#index # POST /clicks(.:format) clicks#create @@ -47,7 +46,6 @@ # lookbook_embed GET /embed/*path(.:format) lookbook/embeds#show # GET /*path(.:format) lookbook/application#not_found -require 'sidekiq/web' require 'lockup' Rails.application.routes.draw do @@ -58,7 +56,6 @@ get 'up' => 'rails/health#show', :as => :rails_health_check mount Lockup::Engine, at: '/lockup' if Rails.env.production? - mount Sidekiq::Web => '/sidekiq' mount Lookbook::Engine, at: '/lookbook' if Rails.env.development? if Rails.configuration.x.cypress diff --git a/config/storage.yml b/config/storage.yml index 12389598..4942ab66 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -5,7 +5,7 @@ test: local: service: Disk root: <%= Rails.root.join("storage") %> -# + # Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) # amazon: # service: S3 diff --git a/db/cable_schema.rb b/db/cable_schema.rb new file mode 100644 index 00000000..23666604 --- /dev/null +++ b/db/cable_schema.rb @@ -0,0 +1,11 @@ +ActiveRecord::Schema[7.1].define(version: 1) do + create_table "solid_cable_messages", force: :cascade do |t| + t.binary "channel", limit: 1024, null: false + t.binary "payload", limit: 536870912, null: false + t.datetime "created_at", null: false + t.integer "channel_hash", limit: 8, null: false + t.index ["channel"], name: "index_solid_cable_messages_on_channel" + t.index ["channel_hash"], name: "index_solid_cable_messages_on_channel_hash" + t.index ["created_at"], name: "index_solid_cable_messages_on_created_at" + end +end diff --git a/db/cache_schema.rb b/db/cache_schema.rb new file mode 100644 index 00000000..6005a297 --- /dev/null +++ b/db/cache_schema.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +ActiveRecord::Schema[7.2].define(version: 1) do + create_table "solid_cache_entries", force: :cascade do |t| + t.binary "key", limit: 1024, null: false + t.binary "value", limit: 536870912, null: false + t.datetime "created_at", null: false + t.integer "key_hash", limit: 8, null: false + t.integer "byte_size", limit: 4, null: false + t.index ["byte_size"], name: "index_solid_cache_entries_on_byte_size" + t.index ["key_hash", "byte_size"], name: "index_solid_cache_entries_on_key_hash_and_byte_size" + t.index ["key_hash"], name: "index_solid_cache_entries_on_key_hash", unique: true + end +end diff --git a/db/migrate/20210522144348_create_clicks.rb b/db/migrate/20210522144348_create_clicks.rb index 635b80f8..0f5348a1 100644 --- a/db/migrate/20210522144348_create_clicks.rb +++ b/db/migrate/20210522144348_create_clicks.rb @@ -1,7 +1,7 @@ class CreateClicks < ActiveRecord::Migration[7.0] def change create_table :clicks do |t| - t.inet :ip, null: false + t.string :ip, null: false t.string :user_agent, null: false t.datetime :created_at, precision: 6, null: false end diff --git a/db/queue_schema.rb b/db/queue_schema.rb new file mode 100644 index 00000000..85194b6a --- /dev/null +++ b/db/queue_schema.rb @@ -0,0 +1,129 @@ +ActiveRecord::Schema[7.1].define(version: 1) do + create_table "solid_queue_blocked_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.string "concurrency_key", null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.index [ "concurrency_key", "priority", "job_id" ], name: "index_solid_queue_blocked_executions_for_release" + t.index [ "expires_at", "concurrency_key" ], name: "index_solid_queue_blocked_executions_for_maintenance" + t.index [ "job_id" ], name: "index_solid_queue_blocked_executions_on_job_id", unique: true + end + + create_table "solid_queue_claimed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.bigint "process_id" + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_claimed_executions_on_job_id", unique: true + t.index [ "process_id", "job_id" ], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id" + end + + create_table "solid_queue_failed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.text "error" + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_failed_executions_on_job_id", unique: true + end + + create_table "solid_queue_jobs", force: :cascade do |t| + t.string "queue_name", null: false + t.string "class_name", null: false + t.text "arguments" + t.integer "priority", default: 0, null: false + t.string "active_job_id" + t.datetime "scheduled_at" + t.datetime "finished_at" + t.string "concurrency_key" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "active_job_id" ], name: "index_solid_queue_jobs_on_active_job_id" + t.index [ "class_name" ], name: "index_solid_queue_jobs_on_class_name" + t.index [ "finished_at" ], name: "index_solid_queue_jobs_on_finished_at" + t.index [ "queue_name", "finished_at" ], name: "index_solid_queue_jobs_for_filtering" + t.index [ "scheduled_at", "finished_at" ], name: "index_solid_queue_jobs_for_alerting" + end + + create_table "solid_queue_pauses", force: :cascade do |t| + t.string "queue_name", null: false + t.datetime "created_at", null: false + t.index [ "queue_name" ], name: "index_solid_queue_pauses_on_queue_name", unique: true + end + + create_table "solid_queue_processes", force: :cascade do |t| + t.string "kind", null: false + t.datetime "last_heartbeat_at", null: false + t.bigint "supervisor_id" + t.integer "pid", null: false + t.string "hostname" + t.text "metadata" + t.datetime "created_at", null: false + t.string "name", null: false + t.index [ "last_heartbeat_at" ], name: "index_solid_queue_processes_on_last_heartbeat_at" + t.index [ "name", "supervisor_id" ], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true + t.index [ "supervisor_id" ], name: "index_solid_queue_processes_on_supervisor_id" + end + + create_table "solid_queue_ready_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_ready_executions_on_job_id", unique: true + t.index [ "priority", "job_id" ], name: "index_solid_queue_poll_all" + t.index [ "queue_name", "priority", "job_id" ], name: "index_solid_queue_poll_by_queue" + end + + create_table "solid_queue_recurring_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "task_key", null: false + t.datetime "run_at", null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_recurring_executions_on_job_id", unique: true + t.index [ "task_key", "run_at" ], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true + end + + create_table "solid_queue_recurring_tasks", force: :cascade do |t| + t.string "key", null: false + t.string "schedule", null: false + t.string "command", limit: 2048 + t.string "class_name" + t.text "arguments" + t.string "queue_name" + t.integer "priority", default: 0 + t.boolean "static", default: true, null: false + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "key" ], name: "index_solid_queue_recurring_tasks_on_key", unique: true + t.index [ "static" ], name: "index_solid_queue_recurring_tasks_on_static" + end + + create_table "solid_queue_scheduled_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "scheduled_at", null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true + t.index [ "scheduled_at", "priority", "job_id" ], name: "index_solid_queue_dispatch_all" + end + + create_table "solid_queue_semaphores", force: :cascade do |t| + t.string "key", null: false + t.integer "value", default: 1, null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "expires_at" ], name: "index_solid_queue_semaphores_on_expires_at" + t.index [ "key", "value" ], name: "index_solid_queue_semaphores_on_key_and_value" + t.index [ "key" ], name: "index_solid_queue_semaphores_on_key", unique: true + end + + add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade +end diff --git a/db/schema.rb b/db/schema.rb index bfdf33e7..ec5cdf32 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,11 +11,8 @@ # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema[8.0].define(version: 2021_05_22_144348) do - # These are extensions that must be enabled in order to support this database - enable_extension "pg_catalog.plpgsql" - create_table "clicks", force: :cascade do |t| - t.inet "ip", null: false + t.string "ip", null: false t.string "user_agent", null: false t.datetime "created_at", null: false end diff --git a/docker/startup.sh b/docker/startup.sh index f7a53fd6..f4e9a841 100755 --- a/docker/startup.sh +++ b/docker/startup.sh @@ -4,22 +4,6 @@ echo "Starting ..." echo "Git commit: $COMMIT_VERSION - $COMMIT_TIME" echo "----------------" -# Wait for Redis -redis_host=$(echo "$REDIS_URL" | awk -F[/:] '{print $4}') -redis_port=$(echo "$REDIS_URL" | awk -F[/:] '{print $5}') -until nc -z -v -w30 "$redis_host" "$redis_port"; do - echo "Waiting for Redis on $redis_host:$redis_port ..." - sleep 1 -done -echo "Redis is up and running!" - -# Wait for PostgreSQL -until nc -z -v -w30 "$DB_HOST" 5432; do - echo "Waiting for PostgreSQL on $DB_HOST:5432 ..." - sleep 1 -done -echo "PostgreSQL is up and running!" - # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then echo "Preparing database..." diff --git a/script/.keep b/script/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/factories/clicks.rb b/spec/factories/clicks.rb index eae33fe3..c27e1a68 100644 --- a/spec/factories/clicks.rb +++ b/spec/factories/clicks.rb @@ -2,8 +2,8 @@ # # Table name: clicks # -# id :bigint not null, primary key -# ip :inet not null +# id :integer not null, primary key +# ip :string not null # user_agent :string not null # created_at :datetime not null # diff --git a/spec/models/click_spec.rb b/spec/models/click_spec.rb index 0cc89adc..2ccbbfe4 100644 --- a/spec/models/click_spec.rb +++ b/spec/models/click_spec.rb @@ -2,8 +2,8 @@ # # Table name: clicks # -# id :bigint not null, primary key -# ip :inet not null +# id :integer not null, primary key +# ip :string not null # user_agent :string not null # created_at :datetime not null # diff --git a/spec/requests/clicks_spec.rb b/spec/requests/clicks_spec.rb index ecb49e37..c0b67df6 100644 --- a/spec/requests/clicks_spec.rb +++ b/spec/requests/clicks_spec.rb @@ -38,7 +38,7 @@ def call(ip) it 'save click and returns http success' do call(ipv6) - expect(Click.last.ip).to eq('2001:0db8:0:0:0:0:0:0') + expect(Click.last.ip).to eq('2001:db8::') expect(response).to have_http_status(:success) expect(Click.last.user_agent).to eq(user_agent) end diff --git a/spec/views/components/about_component_spec.rb b/spec/views/components/about_component_spec.rb index 1540586f..6661423c 100644 --- a/spec/views/components/about_component_spec.rb +++ b/spec/views/components/about_component_spec.rb @@ -3,5 +3,4 @@ it { is_expected.to have_content('Ruby on Rails') } it { is_expected.to have_content(Rails::VERSION::STRING) } - it { is_expected.to have_link(href: '/sidekiq') } end