fly-rails 0.3.5

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.
@@ -0,0 +1,77 @@
1
+ <% if @passenger -%>
2
+ <% if @serverless -%>
3
+ passenger_ctl hook_detached_process /etc/nginx/hook_detached_process;
4
+ passenger_min_instances 0;
5
+ passenger_pool_idle_time 300;
6
+
7
+ <% end -%>
8
+ passenger_log_file /dev/stdout;
9
+ passenger_default_user root;
10
+
11
+ server {
12
+ listen 8080 default_server;
13
+ listen [::]:8080 default_server;
14
+ server_name <%= @app %>.fly.dev;
15
+ root /app/public;
16
+
17
+ access_log /dev/stdout;
18
+ error_log /dev/stdout info;
19
+
20
+ passenger_enabled on;
21
+ passenger_ruby /usr/lib/fullstaq-ruby/versions/<%= @ruby_version %>-jemalloc/bin/ruby;
22
+
23
+ <% if @anycable -%>
24
+ location /cable {
25
+ <%- if @passenger and (@avahi or @nats) -%>
26
+ proxy_pass http://${FLY_REGION}-anycable-go.local:8082/cable;
27
+ proxy_http_version 1.1;
28
+ proxy_set_header Upgrade $${_0_}http_upgrade;
29
+ proxy_set_header Connection "Upgrade";
30
+ proxy_set_header Host $${_0_}host;
31
+ <%- else -%>
32
+ proxy_pass http://localhost:8082/cable;
33
+ proxy_http_version 1.1;
34
+ proxy_set_header Upgrade $http_upgrade;
35
+ proxy_set_header Connection "Upgrade";
36
+ proxy_set_header Host $host;
37
+ <%- end -%>
38
+ }
39
+
40
+ <% elsif @cable -%>
41
+ location /cable {
42
+ passenger_app_group_name <%= @app %>-cable;
43
+ passenger_force_max_concurrent_requests_per_process 0;
44
+ }
45
+
46
+ <% end -%>
47
+ location / {
48
+ passenger_app_group_name <%= @app %>;
49
+ passenger_env_var RAILS_SERVE_STATIC_FILES true;
50
+ passenger_env_var RAILS_LOG_TO_STDOUT true;
51
+ }
52
+
53
+ # Nginx has a default limit of 1 MB for request bodies, which also applies
54
+ # to file uploads. The following line enables uploads of up to 50 MB:
55
+ client_max_body_size 50M;
56
+ }
57
+ <% else -%>
58
+ server {
59
+ listen 8080 default_server;
60
+ listen [::]:8080 default_server;
61
+
62
+ <% if @anycable -%>
63
+ location /cable {
64
+ proxy_pass http://localhost:8082/cable;
65
+ proxy_http_version 1.1;
66
+ proxy_set_header Upgrade $http_upgrade;
67
+ proxy_set_header Connection "Upgrade";
68
+ proxy_set_header Host $host;
69
+ }
70
+
71
+ <% end -%>
72
+ location / {
73
+ proxy_pass http://localhost:8081/;
74
+ proxy_set_header origin 'https://localhost:8081';
75
+ }
76
+ }
77
+ <% end -%>
@@ -0,0 +1,20 @@
1
+ # Restart Action Cable server on Redis connection failures.
2
+ # See: https://github.com/rails/rails/pull/45478
3
+ require 'action_cable/subscription_adapter/redis'
4
+
5
+ module ActionCableRedisListenerPatch
6
+ private
7
+
8
+ def ensure_listener_running
9
+ @thread ||= Thread.new do
10
+ Thread.current.abort_on_exception = true
11
+ conn = @adapter.redis_connection_for_subscriptions
12
+ listen conn
13
+ rescue ::Redis::BaseConnectionError
14
+ @thread = @raw_client = nil
15
+ ::ActionCable.server.restart
16
+ end
17
+ end
18
+ end
19
+
20
+ ActionCable::SubscriptionAdapter::Redis::Listener.prepend(ActionCableRedisListenerPatch)
@@ -0,0 +1,178 @@
1
+ require 'fly-rails/machines'
2
+ require 'fly-rails/hcl'
3
+ require 'fly-rails/actions'
4
+ require 'toml'
5
+ require 'json'
6
+
7
+ config = File.expand_path('config/fly.rb', Rails.application.root)
8
+ if File.exist? config
9
+ @config = Fly::DSL::Config.new
10
+ @config.instance_eval IO.read(config), config
11
+ end
12
+
13
+ namespace :fly do
14
+ desc 'Deploy fly application'
15
+ task :deploy do
16
+ include FlyIoRails::Utils
17
+
18
+ # Get app name, creating one if necessary
19
+ if File.exist? 'fly.toml'
20
+ app = TOML.load_file('fly.toml')['app']
21
+ else
22
+ app = create_app
23
+ end
24
+
25
+ # ensure fly.toml and Dockerfile are present
26
+ action = Fly::Actions.new(app)
27
+ action.generate_toml if @app
28
+ action.generate_fly_config unless File.exist? 'config/fly.rb'
29
+ action.generate_dockerfile
30
+ action.generate_dockerignore
31
+
32
+ # look for missing gems
33
+ action.bundle_gems
34
+
35
+ # build and push an image
36
+ out = FlyIoRails::Utils.tee "flyctl deploy --build-only --push --dockerfile #{action.dockerfile} --ignorefile #{action.ignorefile}"
37
+ image = out[/image:\s+(.*)/, 1]&.strip
38
+
39
+ exit 1 unless image
40
+
41
+ if File.exist? 'main.tf'
42
+ action.terraform(app, image)
43
+ else
44
+ action.generate_ipv4 if @app
45
+ action.generate_ipv6 if @app
46
+ action.deploy(app, image)
47
+ end
48
+
49
+ JSON.parse(`fly apps list --json`).each do |info|
50
+ if info['Name'] == app
51
+ 60.times do
52
+ response = Net::HTTP.get_response(URI::HTTPS.build(host: info['Hostname']))
53
+ puts "Server status: #{response.code} #{response.message}"
54
+ break
55
+ rescue Errno::ECONNRESET
56
+ sleep 0.5
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ desc 'dbus daemon - used for IPC'
63
+ task :dbus_deamon do
64
+ IO.write '/var/lib/dbus/machine-id', `hostname`
65
+ mkdir_p '/var/run/dbus'
66
+ sh 'dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address'
67
+ end
68
+
69
+ desc 'nats based service discovery'
70
+ task :nats_publish, [:formation] do |task, args|
71
+ nats_server = ENV['NATS_SERVER']
72
+
73
+ # start nats server
74
+ if nats_server == 'localhost'
75
+ pid = spawn('nats-server')
76
+ at_exit { Process.kill 7, pid }
77
+ else
78
+ open('/etc/hosts', 'a') do |file|
79
+ host = "#{ENV['FLY_REGION']}-nats-server.local"
80
+ file.puts "#{nats_server}\t#{host}"
81
+ nats_server = host
82
+ end
83
+ end
84
+
85
+ # determine our local 6pn network address
86
+ address = IPSocket.getaddress('fly-local-6pn')
87
+
88
+ # Determine which applications we need addresses for and
89
+ # which applications we can provide addresses for.
90
+ hosts = {}
91
+ needs = []
92
+ args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
93
+ dnsname = "#{ENV['FLY_REGION']}-#{name}.local"
94
+ needs << dnsname
95
+ hosts[dnsname] = address unless count.to_i == 0
96
+ end
97
+
98
+ # share and collect hosts
99
+ require 'nats/client'
100
+ nats = NATS.connect(nats_server)
101
+
102
+ nats.subscribe('query_hosts') do |msg|
103
+ msg.respond hosts.to_json
104
+ end
105
+
106
+ update_hosts = Proc.new do |msg|
107
+ addresses = JSON.parse(msg.data)
108
+
109
+ open('/etc/hosts', 'r+') do |file|
110
+ file.flock(File::LOCK_EX)
111
+ contents = file.read
112
+
113
+ addresses.each do |dnsname, address|
114
+ file.puts "#{address}\t#{dnsname}" unless contents.include? dnsname
115
+ end
116
+ end
117
+
118
+ needs -= hosts.keys
119
+ end
120
+
121
+ nats.request('query_hosts', &update_hosts)
122
+ nats.subscribe('advertise_hosts', &update_hosts)
123
+
124
+ nats.publish('advertise_hosts', hosts.to_json)
125
+
126
+ at_exit { nats.close }
127
+
128
+ # wait for dependencies to be available
129
+ 600.times do
130
+ break if needs.empty?
131
+ sleep 0.1
132
+ end
133
+ end
134
+
135
+ desc 'Zeroconf/avahi/bonjour discovery'
136
+ task :avahi_publish, [:formation] => :dbus_deamon do |task, args|
137
+ pids = []
138
+ pids << spawn('avahi-daemon')
139
+ sleep 0.1
140
+
141
+ ip = IPSocket.getaddress(Socket.gethostname)
142
+ args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
143
+ next if count.to_i == 0
144
+ pids << spawn("avahi-publish -a -R #{ENV['FLY_REGION']}-#{name}.local #{ip}")
145
+ end
146
+
147
+ require 'resolv'
148
+ 100.times do
149
+ begin
150
+ map = {}
151
+ args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
152
+ dnsname = "#{ENV['FLY_REGION']}-#{name}.local"
153
+ resolve = `avahi-resolve-host-name #{dnsname}`
154
+ raise Resolv::ResolvError.new if $?.exitstatus > 0 or resolve.empty?
155
+ map[dnsname] = resolve.split.last
156
+ end
157
+
158
+ open('/etc/hosts', 'a') do |hosts|
159
+ map.each do |dnsname, address|
160
+ hosts.puts "#{address} #{dnsname}"
161
+ end
162
+ end
163
+
164
+ break
165
+ rescue Resolv::ResolvError
166
+ sleep 0.1
167
+ end
168
+ end
169
+
170
+ at_exit do
171
+ pids.each {|pid| Process.kill 7, pid}
172
+ end
173
+ end
174
+ end
175
+
176
+ # Alias, for convenience
177
+ desc 'Deploy fly application'
178
+ task deploy: 'fly:deploy'
@@ -0,0 +1,17 @@
1
+ require 'rack'
2
+ require 'rack/handler/puma'
3
+
4
+ namespace :mock do
5
+ desc 'Mock server - useful for debugging startup issues'
6
+ task :server do
7
+ handler = Rack::Handler::Puma
8
+
9
+ class RackApp
10
+ def call(env)
11
+ [200, {"Content-Type" => "text/plain"}, ["Hello from Fly.io"]]
12
+ end
13
+ end
14
+
15
+ handler.run RackApp.new, Port: ENV['PORT'] || 8080
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fly-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.5
5
+ platform: ruby
6
+ authors:
7
+ - Sam Ruby
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: toml
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description:
28
+ email: rubys@intertwingly.net
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - LICENSE
34
+ - README.md
35
+ - Rakefile
36
+ - lib/fly-rails.rb
37
+ - lib/fly-rails/actions.rb
38
+ - lib/fly-rails/deploy.rb
39
+ - lib/fly-rails/dsl.rb
40
+ - lib/fly-rails/generators.rb
41
+ - lib/fly-rails/hcl.rb
42
+ - lib/fly-rails/machines.rb
43
+ - lib/fly-rails/platforms.rb
44
+ - lib/fly-rails/scanner.rb
45
+ - lib/fly-rails/utils.rb
46
+ - lib/fly-rails/version.rb
47
+ - lib/generators/fly/app_generator.rb
48
+ - lib/generators/fly/config_generator.rb
49
+ - lib/generators/fly/terraform_generator.rb
50
+ - lib/generators/templates/Dockerfile.erb
51
+ - lib/generators/templates/Procfile.fly.erb
52
+ - lib/generators/templates/dockerignore.erb
53
+ - lib/generators/templates/fly.rake.erb
54
+ - lib/generators/templates/fly.rb.erb
55
+ - lib/generators/templates/fly.toml.erb
56
+ - lib/generators/templates/hook_detached_process.erb
57
+ - lib/generators/templates/litefs.yml.erb
58
+ - lib/generators/templates/main.tf.erb
59
+ - lib/generators/templates/nginx.conf.erb
60
+ - lib/generators/templates/patches/action_cable.rb
61
+ - lib/tasks/fly.rake
62
+ - lib/tasks/mock.rake
63
+ homepage: https://github.com/rubys/fly-rails
64
+ licenses:
65
+ - Apache-2.0
66
+ metadata:
67
+ homepage_uri: https://github.com/rubys/fly-rails
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 3.3.5
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Rails support for Fly-io
87
+ test_files: []