fly.io-rails 0.1.7-x86_64-darwin → 0.1.9-x86_64-darwin

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ae3e35b47d99b61b85dea16d2c01b18c3d464ae4dbd47f5ba05b30d8a0b555a
4
- data.tar.gz: c83a04a0ca28c3742deff2436d112ca36ec188adb27b6582dd5d83dace085dff
3
+ metadata.gz: 5e21d219815cad34716d1d4dc5d9e48eea66c60a68c7bf7f4a3f7865214be5bb
4
+ data.tar.gz: 1158bbf8df8f47383070cabab7cbd3a6212139a5f52100ec4d9c1695cd097ec9
5
5
  SHA512:
6
- metadata.gz: c4af4265c38ae8c90fb0840d50ba47e582716b0ee9ee5cc4e8d4a8580515a3a14e0a90ed19e9cd638e83f31fd52c9155b27557aa00bb99028881b7b6eec4b937
7
- data.tar.gz: 59f2359b36893e574d093659459f842bf11a1b40620486f32c3bb23ea53a31612a25620626ece6004678fce51baf343fefe72446483f14588e9dcdd337d7cdab
6
+ metadata.gz: 5bc2e74ec196734a511d791c59ddea29c9c4b2121265729f7bfef5a0f5a9e608841137e4ef4510d2f24c74372ff66dada52aad2aecd2d3eed3daf10c2103797a
7
+ data.tar.gz: 390e7bb1f74ce4cf093182764198f396becff0ed93befab3fbce6ae28fdf0fd92ea0e4c00c0805069609e3704c3f3b6d99af5684c68564f741683cf8954d0090
data/README.md CHANGED
@@ -10,6 +10,25 @@ For usage instructions, see the following guides:
10
10
  * [Lite FS](https://fly.io/docs/rails/advanced-guides/litefs/)
11
11
  * [Terraform](https://fly.io/docs/rails/advanced-guides/terraform/)
12
12
 
13
+ ## Generator options
14
+
15
+ * `--name` name of the application. If a name is not provided, one will be generated for you.
16
+ * `--org` the organization to operate on. Defaults to `personal`.
17
+ * `--region` region to launch the application in. Accepts multiple values, and can be specified multiple times.
18
+ * `--nomad` generates a nomad application instead of a machines application.
19
+ * `--litefs` adds support for replicated sqlite3 databases via [litefs](https://fly.io/blog/introducing-litefs/). Only works on nomad machines currently.
20
+ * `--passenger` run your Rails application with [nginx](https://www.nginx.com/) and [Phusion Passenger](https://www.phusionpassenger.com/).
21
+ * `--serverless` configures your application to exit after 5 minutes of inactivity. Machines will automatically restart when next accessed. Only works with passenger currently.
22
+
23
+ ## Automatically detected features
24
+
25
+ * _ruby_: the deployed application will use the same version of ruby and bundler as your development environment.
26
+ * _node_: if the use of node is detected, node, yarn, and your npm packages will be installed.
27
+ * _sqlite3_: if the production database is sqlite3 a volume will be allocated and the database will be put there.
28
+ * _postgres_: if the production database is postgres a postgres machine will be allocated
29
+ * _redis_: if redis is used for action cable, caching, or sidekiq your redis database will be added to this application. If you don't currently have a redis database, one will be allocated. If redis is used for caching, eviction will be turned on.
30
+ * _sidekiq_: if sidekiq is used it will be launched along side of your rails application.
31
+
13
32
  ## Key files
14
33
 
15
34
  * Entrypoints: [lib/tasks/fly.rake](./lib/tasks/fly.rake), [lib/generators/app_generator.rb](./lib/generators/app_generator.rb), [lib/generators/terraform_generator.rb](.lib/generators/terraform_generator.rb) contain the deploy task, fly:app generator and
Binary file
@@ -24,6 +24,7 @@ module Fly
24
24
  # extract options
25
25
  self.app = app
26
26
  regions = options[:region]&.flatten || []
27
+ @avahi = options[:avahi]
27
28
  @litefs = options[:litefs]
28
29
  @nomad = options[:nomad]
29
30
  @passenger = options[:passenger]
@@ -58,11 +59,43 @@ module Fly
58
59
 
59
60
  # set additional variables based on application source
60
61
  scan_rails_app
62
+ @redis = :internal if options[:redis]
63
+ if File.exist? 'Procfile.fly'
64
+ @redis = :internal if IO.read('Procfile.fly') =~ /^redis/
65
+ end
66
+
67
+ if options[:anycable] and not @anycable
68
+ # read and remove original config
69
+ original_config = YAML.load_file 'config/cable.yml'
70
+ File.unlink 'config/cable.yml'
71
+
72
+ # add and configure anycable-rails
73
+ say_status :run, 'bundle add anycable-rails'
74
+ Bundler.with_original_env do
75
+ system 'bundle add anycable-rails'
76
+ system 'bin/rails generate anycable:setup --skip-heroku --skip-procfile-dev --skip-jwt --devenv=skip'
77
+ end
78
+
79
+ # insert action_cable_meta_tag
80
+ insert_into_file 'app/views/layouts/application.html.erb',
81
+ " <%= action_cable_meta_tag %>\n",
82
+ after: "<%= csp_meta_tag %>\n"
83
+
84
+ # copy production environment to original config
85
+ anycable_config = YAML.load_file 'config/cable.yml'
86
+ original_config['production'] = anycable_config['production']
87
+ File.write 'config/cable.yml', YAML.dump(original_config)
88
+
89
+ @anycable = true
90
+ end
61
91
 
62
92
  # determine processes
63
93
  @procs = {web: 'bin/rails server'}
64
94
  @procs[:web] = "nginx -g 'daemon off;'" if @passenger
65
95
  @procs[:worker] = 'bundle exec sidekiq' if @sidekiq
96
+ @procs[:redis] = 'redis-server /etc/redis/redis.conf' if @redis
97
+ @procs.merge! 'anycable-rpc': 'bundle exec anycable',
98
+ 'anycable-go': '/usr/local/bin/anycable-go --port=8082' if @anycable
66
99
  end
67
100
 
68
101
  def app
@@ -143,7 +176,9 @@ module Fly
143
176
  end
144
177
 
145
178
  def generate_patches
146
- if @redis_cable and not File.exist? 'config/initializers/action_cable.rb'
179
+ if @redis_cable and not @anycable and @redis != :internal and
180
+ not File.exist? 'config/initializers/action_cable.rb'
181
+
147
182
  app
148
183
  template 'patches/action_cable.rb', 'config/initializers/action_cable.rb'
149
184
  end
@@ -204,7 +239,7 @@ module Fly
204
239
  start = Fly::Machines.create_and_start_machine(app, config: config)
205
240
  machine = start[:id]
206
241
 
207
- if !machine
242
+ if not machine
208
243
  STDERR.puts 'Error starting release machine'
209
244
  PP.pp start, STDERR
210
245
  exit 1
@@ -214,24 +249,27 @@ module Fly
214
249
  timeout: 60, state: 'started'
215
250
 
216
251
  # wait for release to copmlete
217
- status = nil
218
252
  5.times do
219
253
  status = Fly::Machines.wait_for_machine app, machine,
220
- timeout: 60, state: 'stopped'
221
- return machine if status[:ok]
254
+ instance_id: start[:instance_id], timeout: 60, state: 'stopped'
255
+ break if status[:ok]
222
256
  end
223
257
 
224
- # wait for release to copmlete
225
- event = nil
226
- 90.times do
227
- sleep 1
228
- status = Fly::Machines.get_a_machine app, machine
229
- event = status[:events]&.first
230
- return machine if event && event[:type] == 'exit'
231
- end
258
+ if status and status[:ok]
259
+ event = nil
260
+ 300.times do
261
+ status = Fly::Machines.get_a_machine app, start[:id]
262
+ event = status[:events]&.first
263
+ break if event[:type] == 'exit'
264
+ sleep 0.2
265
+ end
232
266
 
233
- STDERR.puts event.to_json
234
- exit 1
267
+ exit_code = event&.dig(:request, :exit_event, :exit_code)
268
+ Fly::Machines.delete_machine app, machine if machine
269
+ return event, exit_code, machine
270
+ else
271
+ return status, nil, nil
272
+ end
235
273
  end
236
274
 
237
275
  def launch(app)
@@ -263,7 +301,7 @@ module Fly
263
301
  end
264
302
  end
265
303
 
266
- if @redis and not secrets.include? 'REDIS_URL'
304
+ if @redis and @redis != :internal and not secrets.include? 'REDIS_URL'
267
305
  # Set eviction policy to true if a cache provider, else false.
268
306
  eviction = @redis_cache ? '--enable-eviction' : '--disable-eviction'
269
307
 
@@ -313,22 +351,30 @@ module Fly
313
351
 
314
352
  # perform release
315
353
  say_status :fly, release_config[:env]['SERVER_COMMAND']
316
- machine = release(app, release_config)
317
- Fly::Machines.delete_machine app, machine if machine
318
-
319
- # start proxy, if necessary
320
- endpoint = Fly::Machines::fly_api_hostname!
354
+ event, exit_code, machine = release(app, release_config)
321
355
 
322
- # stop previous instances - list will fail on first run
323
- stdout, stderr, status = Open3.capture3('fly machines list --json')
324
- unless stdout.empty?
325
- JSON.parse(stdout).each do |list|
326
- next if list['id'] == machine
327
- system "fly machines remove --force #{list['id']}"
328
- end
356
+ if exit_code != 0
357
+ STDERR.puts 'Error performing release'
358
+ STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
359
+ STDERR.puts "run 'flyctl logs --instance #{machine}' for more information"
360
+ exit 1
329
361
  end
330
362
  end
331
363
 
364
+ # start proxy, if necessary
365
+ endpoint = Fly::Machines::fly_api_hostname!
366
+
367
+ # stop previous instances - list will fail on first run
368
+ stdout, stderr, status = Open3.capture3('fly machines list --json')
369
+ unless stdout.empty?
370
+ JSON.parse(stdout).each do |list|
371
+ next if list['id'] == machine or list['state'] == 'destroyed'
372
+ cmd = "fly machines remove --force #{list['id']}"
373
+ say_status :run, cmd
374
+ system cmd
375
+ end
376
+ end
377
+
332
378
  # configure sqlite3 (can be overridden by fly.toml)
333
379
  if @sqlite3
334
380
  config[:mounts] = [
@@ -354,38 +400,52 @@ module Fly
354
400
  end
355
401
 
356
402
  # start app
403
+ machines = {}
357
404
  say_status :fly, "start #{app}"
358
- start = Fly::Machines.create_and_start_machine(app, config: config)
359
- machine = start[:id]
405
+ if not toml['processes']
406
+ start = Fly::Machines.create_and_start_machine(app, config: config)
407
+ machines['app'] = start[:id]
408
+ else
409
+ config[:env] ||= {}
410
+ toml['processes'].each do |name, entrypoint|
411
+ config[:env]['SERVER_COMMAND'] = entrypoint
412
+ start = Fly::Machines.create_and_start_machine(app, config: config)
413
+ machines[name] = start[:id]
414
+ end
415
+ end
360
416
 
361
- if !machine
417
+ if machines.empty?
362
418
  STDERR.puts 'Error starting application'
363
419
  PP.pp start, STDERR
364
420
  exit 1
365
421
  end
366
422
 
367
- 5.times do
368
- status = Fly::Machines.wait_for_machine app, machine,
369
- timeout: 60, status: 'started'
370
- return if status[:ok]
423
+ timeout = Time.now + 300
424
+ while Time.now < timeout and not machines.empty?
425
+ machines.each do |name, machine|
426
+ status = Fly::Machines.wait_for_machine app, machine,
427
+ timeout: 10, status: 'started'
428
+ machines.delete name if status[:ok]
429
+ end
371
430
  end
372
431
 
373
- STDERR.puts 'Timeout waiting for application to start'
432
+ unless machines.empty?
433
+ STDERR.puts 'Timeout waiting for application to start'
434
+ end
374
435
  end
375
436
 
376
437
  def terraform(app, image)
377
- # update main.tf with the image name
378
- tf = IO.read('main.tf')
379
- tf[/^\s*image\s*=\s*"(.*?)"/, 1] = image.strip
380
- IO.write 'main.tf', tf
381
-
382
- # find first machine in terraform config file
383
- machines = Fly::HCL.parse(IO.read('main.tf')).find {|block|
384
- block.keys.first == :resource and
385
- block.values.first.keys.first == 'fly_machine'}
438
+ # find first machine using the image ref in terraform config file
439
+ machine = Fly::HCL.parse(IO.read('main.tf')).
440
+ map {|block| block.dig(:resource, 'fly_machine')}.compact.
441
+ find {|machine| machine.values.first[:image] == 'var.image_ref'}
442
+ if not machine
443
+ STDERR.puts 'unable to find fly_machine with image = var.image_ref in main.rf'
444
+ exit 1
445
+ end
386
446
 
387
447
  # extract HCL configuration for the machine
388
- config = machines.values.first.values.first.values.first
448
+ config = machine.values.first
389
449
 
390
450
  # delete HCL specific configuration items
391
451
  %i(services for_each region app name depends_on).each do |key|
@@ -407,40 +467,25 @@ module Fly
407
467
  config[:env] ||= {}
408
468
  config[:env]['SERVER_COMMAND'] = 'bin/rails fly:release'
409
469
 
470
+ # fill in image
471
+ config[:image] = image
472
+
410
473
  # start proxy, if necessary
411
474
  endpoint = Fly::Machines::fly_api_hostname!
412
475
 
413
- # start release machine
414
- STDERR.puts "--> #{config[:env]['SERVER_COMMAND']}"
415
- start = Fly::Machines.create_and_start_machine(app, config: config)
416
- machine = start[:id]
417
-
418
- if !machine
419
- STDERR.puts 'Error starting release machine'
420
- PP.pp start, STDERR
421
- exit 1
422
- end
423
-
424
- # wait for release to copmlete
425
- event = nil
426
- 90.times do
427
- sleep 1
428
- status = Fly::Machines.get_a_machine app, machine
429
- event = status[:events]&.first
430
- break if event && event[:type] == 'exit'
476
+ # perform release, if necessary
477
+ if (IO.read('lib/tasks/fly.rake') rescue '') =~ /^\s*task[ \t]*+:?release"?[ \t]*\S/
478
+ say_status :fly, config[:env]['SERVER_COMMAND']
479
+ event, exit_code, machine = release(app, config)
480
+ else
481
+ exit_code = 0
431
482
  end
432
483
 
433
- # extract exit code
434
- exit_code = event.dig(:request, :exit_event, :exit_code)
435
-
436
484
  if exit_code == 0
437
- # delete release machine
438
- Fly::Machines.delete_machine app, machine
439
-
440
485
  # use terraform apply to deploy
441
486
  ENV['FLY_API_TOKEN'] = `flyctl auth token`.chomp
442
487
  ENV['FLY_HTTP_ENDPOINT'] = endpoint if endpoint
443
- system 'terraform apply -auto-approve'
488
+ system "terraform apply -auto-approve -var=\"image_ref=#{image}\""
444
489
  else
445
490
  STDERR.puts 'Error performing release'
446
491
  STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
@@ -12,7 +12,9 @@ module Fly
12
12
  @postgresql = true
13
13
  end
14
14
 
15
- @sidekiq = IO.read('Gemfile').include? 'sidekiq' rescue false
15
+ gemfile = IO.read('Gemfile') rescue ''
16
+ @sidekiq = gemfile.include? 'sidekiq'
17
+ @anycable = gemfile.include? 'anycable'
16
18
 
17
19
  @cable = ! Dir['app/channels/*.rb'].empty?
18
20
 
@@ -29,6 +29,8 @@ module FlyIoRails
29
29
  end
30
30
 
31
31
  def create_app(name: nil, org: 'personal', regions: [], nomad: false, **rest)
32
+ return if File.exist? 'fly.toml'
33
+
32
34
  cmd = if name
33
35
  "flyctl apps create #{name.inspect} --org #{org.inspect} --machines"
34
36
  else
@@ -1,3 +1,3 @@
1
1
  module Fly_io
2
- VERSION = '0.1.7'
2
+ VERSION = '0.1.9'
3
3
  end
@@ -9,7 +9,10 @@ class AppGenerator < Rails::Generators::Base
9
9
  class_option :region, type: :array, repeatable: true, default: []
10
10
  class_option :nomad, type: :boolean, default: false
11
11
 
12
+ class_option :anycable, type: :boolean, default: false
13
+ class_option :avahi, type: :boolean, default: false
12
14
  class_option :litefs, type: :boolean, default: false
15
+ class_option :redis, type: :boolean, default: false
13
16
  class_option :passenger, type: :boolean, default: false
14
17
  class_option :serverless, type: :boolean, default: false
15
18
 
@@ -9,6 +9,8 @@ class TerraformGenerator < Rails::Generators::Base
9
9
  class_option :region, type: :array, repeatable: true, default: []
10
10
 
11
11
  class_option :litefs, type: :boolean, default: false
12
+ class_option :passenger, type: :boolean, default: false
13
+ class_option :serverless, type: :boolean, default: false
12
14
 
13
15
  def terraform
14
16
  source_paths.push File.expand_path('../templates', __dir__)
@@ -20,6 +22,7 @@ class TerraformGenerator < Rails::Generators::Base
20
22
  action.generate_toml
21
23
  action.generate_dockerfile
22
24
  action.generate_dockerignore
25
+ action.generate_nginx_conf
23
26
  action.generate_terraform
24
27
  action.generate_raketask
25
28
  action.generate_procfile
@@ -30,9 +30,12 @@ ARG BUNDLER_VERSION=<%= @bundler_version %>
30
30
 
31
31
  ARG RAILS_ENV=production
32
32
  ENV RAILS_ENV=${RAILS_ENV}
33
-
34
- ENV RAILS_SERVE_STATIC_FILES true
33
+ <% if @anycable or not @passenger -%>
35
34
  ENV RAILS_LOG_TO_STDOUT true
35
+ <% end -%>
36
+ <% unless @passenger -%>
37
+ ENV RAILS_SERVE_STATIC_FILES true
38
+ <% end -%>
36
39
 
37
40
  ARG BUNDLE_WITHOUT=development:test
38
41
  ARG BUNDLE_PATH=vendor/bundle
@@ -81,9 +84,6 @@ RUN gem update --system --no-document && \
81
84
 
82
85
  COPY Gemfile* ./
83
86
  RUN bundle install && rm -rf vendor/bundle/ruby/*/cache
84
- <% if @procs.length > 1 -%>
85
- RUN gem install foreman
86
- <% end -%>
87
87
 
88
88
  <% if @node -%>
89
89
  #######################################################################
@@ -113,23 +113,27 @@ FROM flyio/litefs:pr-109 AS litefs
113
113
 
114
114
  FROM base
115
115
 
116
+ <% if @passenger -%>
117
+ # add passenger repository
118
+ RUN apt-get install -y dirmngr gnupg apt-transport-https ca-certificates curl && \
119
+ curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | \
120
+ gpg --dearmor > /etc/apt/trusted.gpg.d/phusion.gpg && \
121
+ sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger bullseye main > /etc/apt/sources.list.d/passenger.list'
122
+
123
+ <% end -%>
116
124
  <%
117
125
  @deploy_packages = %w(file vim curl gzip)
118
126
  @deploy_packages += %w(nginx passenger libnginx-mod-http-passenger) if @passenger
119
127
  @deploy_packages << 'postgresql-client' if @postgresql
120
128
  @deploy_packages << 'libsqlite3-0' if @sqlite3
121
129
  @deploy_packages << 'fuse' if @litefs
130
+ @deploy_packages << 'ruby-foreman' if @procs.length > 1
131
+ @deploy_packages << 'redis-server' if @redis == :internal
132
+ @deploy_packages += %w(avahi-daemon avahi-utils libnss-mdns) if @avahi
122
133
  -%>
123
134
  ARG DEPLOY_PACKAGES=<%= @deploy_packages.join(' ').inspect %>
124
135
  ENV DEPLOY_PACKAGES=${DEPLOY_PACKAGES}
125
136
 
126
- <% if @passenger -%>
127
- RUN apt-get install -y dirmngr gnupg apt-transport-https ca-certificates curl && \
128
- curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | \
129
- gpg --dearmor > /etc/apt/trusted.gpg.d/phusion.gpg && \
130
- sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger bullseye main > /etc/apt/sources.list.d/passenger.list'
131
-
132
- <% end -%>
133
137
  RUN --mount=type=cache,id=prod-apt-cache,sharing=locked,target=/var/cache/apt \
134
138
  --mount=type=cache,id=prod-apt-lib,sharing=locked,target=/var/lib/apt \
135
139
  apt-get update -qq && \
@@ -137,6 +141,17 @@ RUN --mount=type=cache,id=prod-apt-cache,sharing=locked,target=/var/cache/apt \
137
141
  ${DEPLOY_PACKAGES} \
138
142
  && rm -rf /var/lib/apt/lists /var/cache/apt/archives
139
143
 
144
+ <% if @anycable -%>
145
+ # install anycable
146
+ RUN curl -L https://github.com/anycable/anycable-go/releases/download/v1.2.1/anycable-go-linux-amd64 -o /usr/local/bin/anycable-go && chmod 755 /usr/local/bin/anycable-go
147
+
148
+ <% end -%>
149
+ <% if @redis == :internal -%>
150
+ # configure redis
151
+ RUN sed -i 's/^daemonize yes/daemonize no/' /etc/redis/redis.conf &&\
152
+ sed -i 's/^logfile/# logfile/' /etc/redis/redis.conf
153
+
154
+ <% end -%>
140
155
  # copy installed gems
141
156
  COPY --from=gems /app /app
142
157
  COPY --from=gems /usr/lib/fullstaq-ruby/versions /usr/lib/fullstaq-ruby/versions
@@ -158,15 +173,32 @@ ADD config/litefs.yml /etc/litefs.yml
158
173
  RUN mkdir /data
159
174
  <% end -%>
160
175
  #######################################################################
176
+ <% if @avahi -%>
177
+
178
+ # configure avahi for ipv6
179
+ RUN sed -i 's/mdns4_minimal/mdns_minimal/' /etc/nsswitch.conf
180
+ <% end -%>
161
181
  <% if @passenger -%>
162
182
 
163
183
  # configure nginx/passenger
164
184
  COPY config/nginx.conf /etc/nginx/sites-available/rails.conf
165
185
  RUN rm /etc/nginx/sites-enabled/default && \
166
- ln -s /etc/nginx/sites-available/rails.conf /etc/nginx/sites-enabled/
186
+ ln -s /etc/nginx/sites-available/rails.conf /etc/nginx/sites-enabled/ && \
187
+ sed -i 's/user .*;/user root;/' /etc/nginx/nginx.conf && \
188
+ sed -i '/^include/i include /etc/nginx/main.d/*.conf;' /etc/nginx/nginx.conf && \
189
+ mkdir /etc/nginx/main.d && \
190
+ echo 'env RAILS_MASTER_KEY;' >> /etc/nginx/main.d/env.conf &&\
191
+ <% if @redis -%>
192
+ echo 'env REDIS_URL;' >> /etc/nginx/main.d/env.conf &&\
193
+ <% end -%>
194
+ <% if @anycable -%>
195
+ echo 'env ANYCABLE_RPC_HOST;' >> /etc/nginx/main.d/env.conf &&\
196
+ echo 'env CABLE_URL;' >> /etc/nginx/main.d/env.conf &&\
197
+ <% end -%>
198
+ echo 'env RAILS_LOG_TO_STDOUT;' >> /etc/nginx/main.d/env.conf
167
199
  <% if @serverless -%>
168
200
  COPY config/hook_detached_process /etc/nginx/
169
- <% end -%>
201
+ <% end -%>
170
202
  <% end -%>
171
203
 
172
204
  # Deploy your application
@@ -17,20 +17,46 @@ namespace :fly do
17
17
  task :release => 'db:migrate'
18
18
  <%- end -%>
19
19
 
20
+ <% end -%>
21
+ <% if @avahi -%>
22
+ task :env do
23
+ <% if @redis -%>
24
+ ENV['REDIS_URL'] = "redis://#{ENV['FLY_REGION']}-redis.local:6379/1"
25
+ <% end -%>
26
+ <% if @anycable -%>
27
+ ENV['ANYCABLE_RPC_HOST'] = "#{ENV['FLY_REGION']}-anycable-rpc.local:50051"
28
+ ENV['CABLE_URL'] = "#{ENV['FLY_REGION']}-anycable-go.local"
29
+ <% end -%>
30
+ end
31
+
20
32
  <% end -%>
21
33
  # SERVER step:
22
34
  # - changes to the filesystem made here are deployed
23
35
  # - full access to secrets, databases
24
36
  # - failures here result in VM being stated, shutdown, and rolled back
25
37
  # to last successful deploy (if any).
26
- <%- if @sqlite3 -%>
27
- task :server => [:swapfile, 'db:migrate'] do
28
- <%- else -%>
29
- task :server => :swapfile do
30
- <%- end -%>
38
+ <%= begin
39
+ deps = [:swapfile]
40
+ deps << 'db:migrate' if @sqlite3
41
+ deps = deps.first if deps.length == 1
42
+
43
+ if @procs.length > 1 ? ':server, [:formation]' : ':server'
44
+ "task :server, [:formation] => #{deps.inspect} do |task, args|"
45
+ else
46
+ "task :server => #{deps.inspect} do"
47
+ end
48
+ end %>
31
49
  <%- if @procs.length > 1 -%>
50
+ formation = args[:formation] || <%= @procs.keys.map {|key| "#{key}=1"}.join(';').inspect %>
51
+ formation.gsub! ';', ','
52
+ <%- if @avahi -%>
53
+ Rake::Task['fly:avahi_publish'].invoke(formation)
54
+ <%- end -%>
32
55
  Bundler.with_original_env do
33
- sh 'foreman start --procfile=Procfile.fly'
56
+ <%- if @avahi -%>
57
+ # Rake::Task['fly:env'].invoke
58
+ <%- end -%>
59
+ sh "foreman start --procfile=Procfile.fly --formation=#{formation}"
34
60
  end
35
61
  <%- else -%>
36
62
  sh <%= @procs.values.first.inspect %>
@@ -53,5 +79,8 @@ namespace :fly do
53
79
  sh 'mkswap /swapfile'
54
80
  sh 'echo 10 > /proc/sys/vm/swappiness'
55
81
  sh 'swapon /swapfile'
82
+ <% if @redis == :internal -%>
83
+ sh 'echo 1 > /proc/sys/vm/overcommit_memory'
84
+ <% end -%>
56
85
  end
57
86
  end
@@ -1,7 +1,9 @@
1
1
  app = "<%= @app %>"
2
2
  kill_signal = "SIGINT"
3
3
  kill_timeout = 5
4
+ <% unless @avahi -%>
4
5
  processes = []
6
+ <% end -%>
5
7
 
6
8
  [build]
7
9
  [build.args]
@@ -23,6 +25,11 @@ processes = []
23
25
  <% else -%>
24
26
  DATABASE_URL = "sqlite3:///mnt/volume/production.sqlite3"
25
27
  <% end -%>
28
+ <% if @avahi -%>
29
+
30
+ [processes]
31
+ app = "bin/rails fly:server[<%= @procs.keys.map {|key| "#{key}=1"}.join(';') %>]"
32
+ <% end -%>
26
33
 
27
34
  [mounts]
28
35
  source = <%= "#{app.gsub('-', '_')}_volume".inspect %>
@@ -3,9 +3,5 @@
3
3
  status = `passenger-status`
4
4
 
5
5
  processes = status[/^Processes\s*:\s*(\d*)/, 1].to_i
6
- <% if @cable -%>
7
- cable = status[/^<%= @app %>-cable.*?\n\n/m]
8
- processes -= 1 if cable and cable =~ /Sessions:\s*[1-9]/
9
- <% end -%>
10
6
 
11
- system 'nginx -s stop' if processes == 0
7
+ system 'nginx -s stop' if processes == 0
@@ -2,11 +2,16 @@ terraform {
2
2
  required_providers {
3
3
  fly = {
4
4
  source = "fly-apps/fly"
5
- version = "0.0.18"
5
+ version = "0.0.20"
6
6
  }
7
7
  }
8
8
  }
9
9
 
10
+ variable "image_ref" {
11
+ type = string
12
+ description = "docker images containing the application"
13
+ }
14
+
10
15
  /* uncomment if you want an internal tunnel
11
16
  provider "fly" {
12
17
  useinternaltunnel = true
@@ -49,7 +54,7 @@ resource "fly_machine" "<%= @appName %>Machine" {
49
54
 
50
55
  app = <%= @app.inspect %>
51
56
  name = "<%= @app %>-${each.value}"
52
- image = "quay.io/evl.ms/fullstaq-ruby:<%= @ruby_version %>-jemalloc-slim"
57
+ image = var.image_ref
53
58
 
54
59
  # Scale application resources
55
60
  cpus = 1
@@ -4,26 +4,44 @@ passenger_min_instances 0;
4
4
  passenger_pool_idle_time 300;
5
5
 
6
6
  <% end -%>
7
+ passenger_log_file /dev/stdout;
8
+ passenger_default_user root;
9
+
7
10
  server {
8
- listen 8080;
11
+ listen 8080 default_server;
12
+ listen [::]:8080 default_server;
9
13
  server_name <%= @app %>.fly.dev;
10
14
  root /app/public;
11
15
 
16
+ access_log /dev/stdout;
17
+ error_log /dev/stdout info;
18
+
12
19
  passenger_enabled on;
13
20
  passenger_ruby /usr/lib/fullstaq-ruby/versions/<%= @ruby_version %>-jemalloc/bin/ruby;
14
21
 
15
- <% if @cable -%>
16
- location / {
17
- passenger_app_group_name <%= @app%>;
18
- }
22
+ <% if @anycable -%>
23
+ location /cable {
24
+ proxy_pass http://localhost:8082/cable;
25
+ proxy_http_version 1.1;
26
+ proxy_set_header Upgrade $http_upgrade;
27
+ proxy_set_header Connection "Upgrade";
28
+ proxy_set_header Host $host;
29
+ }
19
30
 
20
- location /cable {
21
- passenger_app_group_name <%= @app%>-cable;
22
- passenger_force_max_concurrent_requests_per_process 0;
23
- }
31
+ <% elsif @cable -%>
32
+ location /cable {
33
+ passenger_app_group_name <%= @app %>-cable;
34
+ passenger_force_max_concurrent_requests_per_process 0;
35
+ }
24
36
 
25
37
  <% end -%>
38
+ location / {
39
+ passenger_app_group_name <%= @app %>;
40
+ passenger_env_var RAILS_SERVE_STATIC_FILES true;
41
+ passenger_env_var RAILS_LOG_TO_STDOUT true;
42
+ }
43
+
26
44
  # Nginx has a default limit of 1 MB for request bodies, which also applies
27
45
  # to file uploads. The following line enables uploads of up to 50 MB:
28
46
  client_max_body_size 50M;
29
- }
47
+ }
data/lib/tasks/fly.rake CHANGED
@@ -37,6 +37,42 @@ namespace :fly do
37
37
  action.generate_ipv6 if @app
38
38
  action.deploy(app, image)
39
39
  end
40
+
41
+ JSON.parse(`fly apps list --json`).each do |info|
42
+ if info['Name'] == app
43
+ 60.times do
44
+ response = Net::HTTP.get_response(URI::HTTPS.build(host: info['Hostname']))
45
+ puts "Server status: #{response.code} #{response.message}"
46
+ break
47
+ rescue Errno::ECONNRESET
48
+ sleep 0.5
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ desc 'dbus daemon - used for IPC'
55
+ task :dbus_deamon do
56
+ IO.write '/var/lib/dbus/machine-id', `hostname`
57
+ mkdir_p '/var/run/dbus'
58
+ sh 'dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address'
59
+ end
60
+
61
+ desc 'Zeroconf/avahi/bonjour discovery'
62
+ task :avahi_publish, [:formation] => :dbus_deamon do |task, args|
63
+ pids = []
64
+ pids << spawn('avahi-daemon')
65
+ sleep 0.1
66
+
67
+ ip = IPSocket.getaddress(Socket.gethostname)
68
+ args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
69
+ next if count.to_i == 0
70
+ pids << spawn("avahi-publish -a -R #{ENV['FLY_REGION']}-#{name}.local #{ip}")
71
+ end
72
+
73
+ at_exit do
74
+ pids.each {|pid| Process.kill 7, pid}
75
+ end
40
76
  end
41
77
  end
42
78
 
@@ -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 CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fly.io-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.9
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Sam Ruby
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-07 00:00:00.000000000 Z
11
+ date: 2022-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fly-ruby
@@ -74,11 +74,12 @@ files:
74
74
  - lib/generators/templates/nginx.conf.erb
75
75
  - lib/generators/templates/patches/action_cable.rb
76
76
  - lib/tasks/fly.rake
77
- homepage: https://github.com/rubys/fly-io.rails
77
+ - lib/tasks/mock.rake
78
+ homepage: https://github.com/rubys/fly.io-rails
78
79
  licenses:
79
80
  - Apache-2.0
80
81
  metadata:
81
- homepage_uri: https://github.com/rubys/fly-io.rails
82
+ homepage_uri: https://github.com/rubys/fly.io-rails
82
83
  post_install_message:
83
84
  rdoc_options: []
84
85
  require_paths: