scatter_gather 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.cursor/rules/instructions.mdc +21 -0
  3. data/.github/dependabot.yml +12 -0
  4. data/.github/workflows/ci.yml +55 -0
  5. data/CHANGELOG.md +7 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE.md +21 -0
  8. data/README.md +86 -0
  9. data/Rakefile +32 -0
  10. data/bin/console +11 -0
  11. data/bin/setup +8 -0
  12. data/bin/test +5 -0
  13. data/lib/generators/install_generator.rb +33 -0
  14. data/lib/generators/scatter_gather_migration_001.rb.erb +16 -0
  15. data/lib/scatter_gather/version.rb +5 -0
  16. data/lib/scatter_gather.rb +196 -0
  17. data/lib/tasks/scatter_gather_tasks.rake +8 -0
  18. data/rbi/scatter_gather.rbi +135 -0
  19. data/scatter_gather-0.1.19.gem +0 -0
  20. data/scatter_gather.gemspec +46 -0
  21. data/sig/scatter_gather.rbs +116 -0
  22. data/test/dummy/Rakefile +8 -0
  23. data/test/dummy/app/assets/stylesheets/application.css +1 -0
  24. data/test/dummy/app/controllers/application_controller.rb +6 -0
  25. data/test/dummy/app/helpers/application_helper.rb +4 -0
  26. data/test/dummy/app/jobs/application_job.rb +9 -0
  27. data/test/dummy/app/mailers/application_mailer.rb +6 -0
  28. data/test/dummy/app/models/application_record.rb +5 -0
  29. data/test/dummy/app/views/layouts/application.html.erb +27 -0
  30. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  31. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  32. data/test/dummy/app/views/pwa/manifest.json.erb +22 -0
  33. data/test/dummy/app/views/pwa/service-worker.js +26 -0
  34. data/test/dummy/bin/dev +2 -0
  35. data/test/dummy/bin/rails +4 -0
  36. data/test/dummy/bin/rake +4 -0
  37. data/test/dummy/bin/setup +34 -0
  38. data/test/dummy/config/application.rb +28 -0
  39. data/test/dummy/config/boot.rb +7 -0
  40. data/test/dummy/config/cable.yml +10 -0
  41. data/test/dummy/config/database.sqlite3.yml +32 -0
  42. data/test/dummy/config/database.yml +32 -0
  43. data/test/dummy/config/environment.rb +7 -0
  44. data/test/dummy/config/environments/development.rb +71 -0
  45. data/test/dummy/config/environments/production.rb +91 -0
  46. data/test/dummy/config/environments/test.rb +55 -0
  47. data/test/dummy/config/initializers/content_security_policy.rb +27 -0
  48. data/test/dummy/config/initializers/filter_parameter_logging.rb +10 -0
  49. data/test/dummy/config/initializers/inflections.rb +18 -0
  50. data/test/dummy/config/locales/en.yml +31 -0
  51. data/test/dummy/config/puma.rb +40 -0
  52. data/test/dummy/config/routes.rb +16 -0
  53. data/test/dummy/config/storage.yml +34 -0
  54. data/test/dummy/config.ru +8 -0
  55. data/test/dummy/db/migrate/20250101000001_add_scatter_gather_completions.rb +16 -0
  56. data/test/dummy/db/schema.rb +23 -0
  57. data/test/dummy/public/400.html +114 -0
  58. data/test/dummy/public/404.html +114 -0
  59. data/test/dummy/public/406-unsupported-browser.html +114 -0
  60. data/test/dummy/public/422.html +114 -0
  61. data/test/dummy/public/500.html +114 -0
  62. data/test/dummy/public/icon.png +0 -0
  63. data/test/dummy/public/icon.svg +3 -0
  64. data/test/scatter_gather_test.rb +180 -0
  65. data/test/test_helper.rb +17 -0
  66. metadata +285 -0
@@ -0,0 +1,135 @@
1
+ # typed: strong
2
+ # Scatter-Gather Pattern for ActiveJob
3
+ #
4
+ # This module provides a scatter-gather pattern for coordinating job execution.
5
+ # Jobs can wait for other jobs to complete before executing, with configurable
6
+ # polling, retry, and timeout behavior.
7
+ #
8
+ # Example workflow:
9
+ # # Start some scatter jobs
10
+ # email_parser_job = EmailParserJob.perform_later(email_id: 123)
11
+ # attachment_processor_job = AttachmentProcessorJob.perform_later(email_id: 123)
12
+ # ai_categorizer_job = AICategorizerJob.perform_later(email_id: 123)
13
+ #
14
+ # # Create a gather job that waits for all dependencies to complete
15
+ # NotifyCompleteJob.gather(email_parser_job, attachment_processor_job, ai_categorizer_job).perform_later
16
+ #
17
+ # The gather job will:
18
+ # - Check if all dependencies are complete
19
+ # - If complete: enqueue the target job immediately
20
+ # - If not complete: poll every 2 seconds (configurable), re-enqueuing itself
21
+ # - After 10 attempts (configurable): discard with error reporting
22
+ #
23
+ # Configuration options:
24
+ # - max_attempts: Number of polling attempts before giving up (default: 10)
25
+ # - poll_interval: Time between polling attempts (default: 2.seconds)
26
+ #
27
+ # Example with custom configuration:
28
+ # TouchingJob.gather(jobs, poll_interval: 0.2.seconds, max_attempts: 4).perform_later(final_path)
29
+ module ScatterGather
30
+ extend ActiveSupport::Concern
31
+ DEFAULT_GATHER_CONFIG = T.let({
32
+ max_attempts: 10,
33
+ poll_interval: 2.seconds
34
+ }.freeze, T.untyped)
35
+ VERSION = T.let("0.1.0", T.untyped)
36
+
37
+ # sord omit - no YARD return type given, using untyped
38
+ # Updates the completions table with the status of this job
39
+ sig { returns(T.untyped) }
40
+ def register_completion_for_gathering; end
41
+
42
+ class Completion < ActiveRecord::Base
43
+ # sord omit - no YARD type given for "active_job_ids", using untyped
44
+ # sord omit - no YARD return type given, using untyped
45
+ sig { params(active_job_ids: T.untyped).returns(T.untyped) }
46
+ def self.collect_statuses(active_job_ids); end
47
+ end
48
+
49
+ # Proxy class that mimics ActiveJob behavior for gather jobs
50
+ class GatherJobProxy
51
+ # sord omit - no YARD type given for "target_class", using untyped
52
+ # sord omit - no YARD type given for "ids", using untyped
53
+ # sord omit - no YARD type given for "config", using untyped
54
+ sig { params(target_class: T.untyped, ids: T.untyped, config: T.untyped).void }
55
+ def initialize(target_class, ids, config); end
56
+
57
+ # Mimic ActiveJob's perform_later method
58
+ #
59
+ # _@param_ `args` — Positional arguments to pass to the target job's perform method
60
+ #
61
+ # _@param_ `kwargs` — Keyword arguments to pass to the target job's perform method
62
+ #
63
+ # _@return_ — Enqueues the gather job
64
+ sig { params(args: T::Array[T.untyped], kwargs: T::Hash[T.untyped, T.untyped]).void }
65
+ def perform_later(*args, **kwargs); end
66
+ end
67
+
68
+ # Custom exception for when gather job exhausts attempts
69
+ class DependencyTimeoutError < StandardError
70
+ # sord omit - no YARD type given for "max_attempts", using untyped
71
+ # sord omit - no YARD type given for "dependency_status", using untyped
72
+ sig { params(max_attempts: T.untyped, dependency_status: T.untyped).void }
73
+ def initialize(max_attempts, dependency_status); end
74
+
75
+ # sord omit - no YARD type given for :dependency_status, using untyped
76
+ # Returns the value of attribute dependency_status.
77
+ sig { returns(T.untyped) }
78
+ attr_reader :dependency_status
79
+ end
80
+
81
+ # Internal job class for polling and coordinating gather operations
82
+ class GatherJob < ActiveJob::Base
83
+ include ScatterGather
84
+
85
+ # sord omit - no YARD return type given, using untyped
86
+ sig { returns(T.untyped) }
87
+ def logger; end
88
+
89
+ # sord omit - no YARD type given for "wait_for_active_job_ids:", using untyped
90
+ # sord omit - no YARD type given for "target_job:", using untyped
91
+ # sord omit - no YARD type given for "gather_config:", using untyped
92
+ # sord omit - no YARD type given for "remaining_attempts:", using untyped
93
+ # sord omit - no YARD return type given, using untyped
94
+ sig do
95
+ params(
96
+ wait_for_active_job_ids: T.untyped,
97
+ target_job: T.untyped,
98
+ gather_config: T.untyped,
99
+ remaining_attempts: T.untyped
100
+ ).returns(T.untyped)
101
+ end
102
+ def perform(wait_for_active_job_ids:, target_job:, gather_config:, remaining_attempts:); end
103
+
104
+ # sord omit - no YARD type given for "hash", using untyped
105
+ # sord omit - no YARD return type given, using untyped
106
+ sig { params(hash: T.untyped).returns(T.untyped) }
107
+ def tally_in_logger_format(hash); end
108
+
109
+ # sord omit - no YARD type given for "target_job", using untyped
110
+ # sord omit - no YARD return type given, using untyped
111
+ sig { params(target_job: T.untyped).returns(T.untyped) }
112
+ def perform_target_later_from_args(target_job); end
113
+
114
+ # sord omit - no YARD return type given, using untyped
115
+ # Updates the completions table with the status of this job
116
+ sig { returns(T.untyped) }
117
+ def register_completion_for_gathering; end
118
+ end
119
+
120
+ # The generator is used to install ScatterGather. It adds the migration that creates
121
+ # the scatter_gather_completions table.
122
+ # Run it with `bin/rails g scatter_gather:install` in your console.
123
+ class InstallGenerator < Rails::Generators::Base
124
+ include ActiveRecord::Generators::Migration
125
+
126
+ # sord omit - no YARD return type given, using untyped
127
+ # Generates migration file that creates the scatter_gather_completions table.
128
+ sig { returns(T.untyped) }
129
+ def create_migration_file; end
130
+
131
+ # sord omit - no YARD return type given, using untyped
132
+ sig { returns(T.untyped) }
133
+ def migration_version; end
134
+ end
135
+ end
Binary file
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/scatter_gather/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "scatter_gather"
7
+ spec.version = ScatterGather::VERSION
8
+ spec.authors = ["Julik Tarkhanov"]
9
+ spec.email = ["me@julik.nl"]
10
+ spec.license = "MIT"
11
+
12
+ spec.summary = "Effortless step workflows that embed nicely inside Rails"
13
+ spec.description = "Step workflows for Rails/ActiveRecord"
14
+ spec.homepage = "https://scattergather.dev"
15
+ spec.required_ruby_version = ">= 3.1.0"
16
+
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/julik/scatter_gather"
21
+ spec.metadata["changelog_uri"] = "https://github.com/julik/scatter_gather/blob/main/CHANGELOG.md"
22
+
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ File.basename(f).start_with?(".")
26
+ end
27
+ end
28
+
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_dependency "activerecord", ">= 7"
34
+ spec.add_dependency "activejob"
35
+ spec.add_dependency "railties"
36
+
37
+ spec.add_development_dependency "minitest"
38
+ spec.add_development_dependency "rails", "~> 7.0"
39
+ spec.add_development_dependency "sqlite3"
40
+ spec.add_development_dependency "rake", "~> 13.0"
41
+ spec.add_development_dependency "standard", "~> 1.50.0", "< 2.0"
42
+ spec.add_development_dependency "magic_frozen_string_literal"
43
+ spec.add_development_dependency "yard"
44
+ spec.add_development_dependency "redcarpet" # needed for the yard gem to enable Github Flavored Markdown
45
+ spec.add_development_dependency "sord"
46
+ end
@@ -0,0 +1,116 @@
1
+ # Scatter-Gather Pattern for ActiveJob
2
+ #
3
+ # This module provides a scatter-gather pattern for coordinating job execution.
4
+ # Jobs can wait for other jobs to complete before executing, with configurable
5
+ # polling, retry, and timeout behavior.
6
+ #
7
+ # Example workflow:
8
+ # # Start some scatter jobs
9
+ # email_parser_job = EmailParserJob.perform_later(email_id: 123)
10
+ # attachment_processor_job = AttachmentProcessorJob.perform_later(email_id: 123)
11
+ # ai_categorizer_job = AICategorizerJob.perform_later(email_id: 123)
12
+ #
13
+ # # Create a gather job that waits for all dependencies to complete
14
+ # NotifyCompleteJob.gather(email_parser_job, attachment_processor_job, ai_categorizer_job).perform_later
15
+ #
16
+ # The gather job will:
17
+ # - Check if all dependencies are complete
18
+ # - If complete: enqueue the target job immediately
19
+ # - If not complete: poll every 2 seconds (configurable), re-enqueuing itself
20
+ # - After 10 attempts (configurable): discard with error reporting
21
+ #
22
+ # Configuration options:
23
+ # - max_attempts: Number of polling attempts before giving up (default: 10)
24
+ # - poll_interval: Time between polling attempts (default: 2.seconds)
25
+ #
26
+ # Example with custom configuration:
27
+ # TouchingJob.gather(jobs, poll_interval: 0.2.seconds, max_attempts: 4).perform_later(final_path)
28
+ module ScatterGather
29
+ extend ActiveSupport::Concern
30
+ DEFAULT_GATHER_CONFIG: untyped
31
+ VERSION: untyped
32
+
33
+ # sord omit - no YARD return type given, using untyped
34
+ # Updates the completions table with the status of this job
35
+ def register_completion_for_gathering: () -> untyped
36
+
37
+ class Completion < ActiveRecord::Base
38
+ # sord omit - no YARD type given for "active_job_ids", using untyped
39
+ # sord omit - no YARD return type given, using untyped
40
+ def self.collect_statuses: (untyped active_job_ids) -> untyped
41
+ end
42
+
43
+ # Proxy class that mimics ActiveJob behavior for gather jobs
44
+ class GatherJobProxy
45
+ # sord omit - no YARD type given for "target_class", using untyped
46
+ # sord omit - no YARD type given for "ids", using untyped
47
+ # sord omit - no YARD type given for "config", using untyped
48
+ def initialize: (untyped target_class, untyped ids, untyped config) -> void
49
+
50
+ # Mimic ActiveJob's perform_later method
51
+ #
52
+ # _@param_ `args` — Positional arguments to pass to the target job's perform method
53
+ #
54
+ # _@param_ `kwargs` — Keyword arguments to pass to the target job's perform method
55
+ #
56
+ # _@return_ — Enqueues the gather job
57
+ def perform_later: (*::Array[untyped] args, **::Hash[untyped, untyped] kwargs) -> void
58
+ end
59
+
60
+ # Custom exception for when gather job exhausts attempts
61
+ class DependencyTimeoutError < StandardError
62
+ # sord omit - no YARD type given for "max_attempts", using untyped
63
+ # sord omit - no YARD type given for "dependency_status", using untyped
64
+ def initialize: (untyped max_attempts, untyped dependency_status) -> void
65
+
66
+ # sord omit - no YARD type given for :dependency_status, using untyped
67
+ # Returns the value of attribute dependency_status.
68
+ attr_reader dependency_status: untyped
69
+ end
70
+
71
+ # Internal job class for polling and coordinating gather operations
72
+ class GatherJob < ActiveJob::Base
73
+ include ScatterGather
74
+
75
+ # sord omit - no YARD return type given, using untyped
76
+ def logger: () -> untyped
77
+
78
+ # sord omit - no YARD type given for "wait_for_active_job_ids:", using untyped
79
+ # sord omit - no YARD type given for "target_job:", using untyped
80
+ # sord omit - no YARD type given for "gather_config:", using untyped
81
+ # sord omit - no YARD type given for "remaining_attempts:", using untyped
82
+ # sord omit - no YARD return type given, using untyped
83
+ def perform: (
84
+ wait_for_active_job_ids: untyped,
85
+ target_job: untyped,
86
+ gather_config: untyped,
87
+ remaining_attempts: untyped
88
+ ) -> untyped
89
+
90
+ # sord omit - no YARD type given for "hash", using untyped
91
+ # sord omit - no YARD return type given, using untyped
92
+ def tally_in_logger_format: (untyped hash) -> untyped
93
+
94
+ # sord omit - no YARD type given for "target_job", using untyped
95
+ # sord omit - no YARD return type given, using untyped
96
+ def perform_target_later_from_args: (untyped target_job) -> untyped
97
+
98
+ # sord omit - no YARD return type given, using untyped
99
+ # Updates the completions table with the status of this job
100
+ def register_completion_for_gathering: () -> untyped
101
+ end
102
+
103
+ # The generator is used to install ScatterGather. It adds the migration that creates
104
+ # the scatter_gather_completions table.
105
+ # Run it with `bin/rails g scatter_gather:install` in your console.
106
+ class InstallGenerator < Rails::Generators::Base
107
+ include ActiveRecord::Generators::Migration
108
+
109
+ # sord omit - no YARD return type given, using untyped
110
+ # Generates migration file that creates the scatter_gather_completions table.
111
+ def create_migration_file: () -> untyped
112
+
113
+ # sord omit - no YARD return type given, using untyped
114
+ def migration_version: () -> untyped
115
+ end
116
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
4
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
5
+
6
+ require_relative "config/application"
7
+
8
+ Rails.application.load_tasks
@@ -0,0 +1 @@
1
+ /* Application styles */
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationController < ActionController::Base
4
+ # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
5
+ allow_browser versions: :modern
6
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApplicationHelper
4
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationJob < ActiveJob::Base
4
+ # Automatically retry jobs that encountered a deadlock
5
+ # retry_on ActiveRecord::Deadlocked
6
+
7
+ # Most jobs are safe to ignore if the underlying records are no longer available
8
+ # discard_on ActiveJob::DeserializationError
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationMailer < ActionMailer::Base
4
+ default from: "from@example.com"
5
+ layout "mailer"
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationRecord < ActiveRecord::Base
4
+ primary_abstract_class
5
+ end
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= content_for(:title) || "Dummy" %></title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <meta name="apple-mobile-web-app-capable" content="yes">
7
+ <meta name="mobile-web-app-capable" content="yes">
8
+ <%= csrf_meta_tags %>
9
+ <%= csp_meta_tag %>
10
+
11
+ <%= yield :head %>
12
+
13
+ <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
14
+ <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
15
+
16
+ <link rel="icon" href="/icon.png" type="image/png">
17
+ <link rel="icon" href="/icon.svg" type="image/svg+xml">
18
+ <link rel="apple-touch-icon" href="/icon.png">
19
+
20
+ <%# Includes all stylesheet files in app/assets/stylesheets %>
21
+ <%= stylesheet_link_tag "application" %>
22
+ </head>
23
+
24
+ <body>
25
+ <%= yield %>
26
+ </body>
27
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "Dummy",
3
+ "icons": [
4
+ {
5
+ "src": "/icon.png",
6
+ "type": "image/png",
7
+ "sizes": "512x512"
8
+ },
9
+ {
10
+ "src": "/icon.png",
11
+ "type": "image/png",
12
+ "sizes": "512x512",
13
+ "purpose": "maskable"
14
+ }
15
+ ],
16
+ "start_url": "/",
17
+ "display": "standalone",
18
+ "scope": "/",
19
+ "description": "Dummy.",
20
+ "theme_color": "red",
21
+ "background_color": "red"
22
+ }
@@ -0,0 +1,26 @@
1
+ // Add a service worker for processing Web Push notifications:
2
+ //
3
+ // self.addEventListener("push", async (event) => {
4
+ // const { title, options } = await event.data.json()
5
+ // event.waitUntil(self.registration.showNotification(title, options))
6
+ // })
7
+ //
8
+ // self.addEventListener("notificationclick", function(event) {
9
+ // event.notification.close()
10
+ // event.waitUntil(
11
+ // clients.matchAll({ type: "window" }).then((clientList) => {
12
+ // for (let i = 0; i < clientList.length; i++) {
13
+ // let client = clientList[i]
14
+ // let clientPath = (new URL(client.url)).pathname
15
+ //
16
+ // if (clientPath == event.notification.data.path && "focus" in client) {
17
+ // return client.focus()
18
+ // }
19
+ // }
20
+ //
21
+ // if (clients.openWindow) {
22
+ // return clients.openWindow(event.notification.data.path)
23
+ // }
24
+ // })
25
+ // )
26
+ // })
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ exec "./bin/rails", "server", *ARGV
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path("../config/application", __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ APP_ROOT = File.expand_path("..", __dir__)
5
+
6
+ def system!(*args)
7
+ system(*args, exception: true)
8
+ end
9
+
10
+ FileUtils.chdir APP_ROOT do
11
+ # This script is a way to set up or update your development environment automatically.
12
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
13
+ # Add necessary setup steps to this file.
14
+
15
+ puts "== Installing dependencies =="
16
+ system("bundle check") || system!("bundle install")
17
+
18
+ # puts "\n== Copying sample files =="
19
+ # unless File.exist?("config/database.yml")
20
+ # FileUtils.cp "config/database.yml.sample", "config/database.yml"
21
+ # end
22
+
23
+ puts "\n== Preparing database =="
24
+ system! "bin/rails db:prepare"
25
+
26
+ puts "\n== Removing old logs and tempfiles =="
27
+ system! "bin/rails log:clear tmp:clear"
28
+
29
+ unless ARGV.include?("--skip-server")
30
+ puts "\n== Starting development server =="
31
+ $stdout.flush # flush the output before exec(2) so that it displays
32
+ exec "bin/dev"
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "boot"
4
+
5
+ require "rails/all"
6
+
7
+ # Require the gems listed in Gemfile, including any gems
8
+ # you've limited to :test, :development, or :production.
9
+ Bundler.require(*Rails.groups)
10
+
11
+ module Dummy
12
+ class Application < Rails::Application
13
+ config.load_defaults Rails::VERSION::STRING.to_f
14
+
15
+ # Please, add to the `ignore` list any other `lib` subdirectories that do
16
+ # not contain `.rb` files, or that should not be reloaded or eager loaded.
17
+ # Common ones are `templates`, `generators`, or `middleware`, for example.
18
+ config.autoload_lib(ignore: %w[assets tasks])
19
+
20
+ # Configuration for the application, engines, and railties goes here.
21
+ #
22
+ # These settings can be overridden in specific environments using the files
23
+ # in config/environments, which are processed later.
24
+ #
25
+ # config.time_zone = "Central Time (US & Canada)"
26
+ # config.eager_load_paths << Rails.root.join("extras")
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Set up gems listed in the Gemfile.
4
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
5
+
6
+ require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
7
+ $LOAD_PATH.unshift File.expand_path("../../../lib", __dir__)
@@ -0,0 +1,10 @@
1
+ development:
2
+ adapter: async
3
+
4
+ test:
5
+ adapter: test
6
+
7
+ production:
8
+ adapter: redis
9
+ url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10
+ channel_prefix: dummy_production
@@ -0,0 +1,32 @@
1
+ # SQLite. Versions 3.8.0 and up are supported.
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem "sqlite3"
6
+ #
7
+ default: &default
8
+ adapter: sqlite3
9
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10
+ timeout: 5000
11
+
12
+ development:
13
+ <<: *default
14
+ database: storage/development.sqlite3
15
+
16
+ # Warning: The database defined as "test" will be erased and
17
+ # re-generated from your development database when you run "rake".
18
+ # Do not set this db to the same as development or production.
19
+ test:
20
+ <<: *default
21
+ database: storage/test.sqlite3
22
+
23
+
24
+ # SQLite3 write its data on the local filesystem, as such it requires
25
+ # persistent disks. If you are deploying to a managed service, you should
26
+ # make sure it provides disk persistence, as many don't.
27
+ #
28
+ # Similarly, if you deploy your application as a Docker container, you must
29
+ # ensure the database is located in a persisted volume.
30
+ production:
31
+ <<: *default
32
+ # database: path/to/persistent/storage/production.sqlite3
@@ -0,0 +1,32 @@
1
+ # SQLite. Versions 3.8.0 and up are supported.
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem "sqlite3"
6
+ #
7
+ default: &default
8
+ adapter: sqlite3
9
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10
+ timeout: 5000
11
+
12
+ development:
13
+ <<: *default
14
+ database: storage/development.sqlite3
15
+
16
+ # Warning: The database defined as "test" will be erased and
17
+ # re-generated from your development database when you run "rake".
18
+ # Do not set this db to the same as development or production.
19
+ test:
20
+ <<: *default
21
+ database: storage/test.sqlite3
22
+
23
+
24
+ # SQLite3 write its data on the local filesystem, as such it requires
25
+ # persistent disks. If you are deploying to a managed service, you should
26
+ # make sure it provides disk persistence, as many don't.
27
+ #
28
+ # Similarly, if you deploy your application as a Docker container, you must
29
+ # ensure the database is located in a persisted volume.
30
+ production:
31
+ <<: *default
32
+ # database: path/to/persistent/storage/production.sqlite3
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Load the Rails application.
4
+ require_relative "application"
5
+
6
+ # Initialize the Rails application.
7
+ Rails.application.initialize!