この記事は2016/5/31までの内容です。
Herokuのappを二つ使って交互起動で常時運用(Sinatra版) - 別館 子子子子子子(ねこのここねこ)
では Sinatra で交互起動させましたが、大したこともしてないので Sinatra を動かすほどでもない気がしてきました。ということで Rack で同様のことをするスクリプトを書きました。
config.ru
先の投稿では alternateapps.rb というスクリプト名にしましたが、今回は Rack アプリケーションなので config.ru にしました。 rackup で起動します。
もしも通常の Ruby スクリプトとして使いたい場合には Sinatra学習の基礎としてRackを学ぶ - 別館 子子子子子子(ねこのここねこ) の[ruckup を使わず ruby スクリプトとして起動]を見てください。
なお、Heroku のデフォルトサーバアプリである WEBrick だと Heroku からの TERM シグナルに対してエラーメッセージ(FATAL SignalException: SIGTERM)が出るので、エラー回避をするために trap(:TERM)
節を入れています。
#!/usr/bin/env ruby # coding: utf-8 require 'rack' require 'dotenv' require 'open-uri' require 'json' $stdout.sync = true $update = nil Dotenv.load trap(:TERM) do Rack::Handler::WEBrick.shutdown end class HerokuAlternate def call(env) request = Rack::Request.new(env) responce = case request.path_info when "/update" $update = true puts "Recieve access from another app. Stop the cron processes." body = JSON.dump({status: 'Update'}) Rack::Response.new(body, 200, 'Content-Type' => 'text/plain') else Rack::Response.new("Not Found", 404, 'Content-Type' => 'text/plain') end responce.finish end end certs = [ENV['BASIC_AUTH_USERNAME'], ENV['BASIC_AUTH_PASSWORD']] begin JSON.parse(open(ENV['ANOTHER_SITE_URL'], {:http_basic_authentication => certs}).read) rescue Errno::ECONNREFUSED, OpenURI::HTTPError puts "Another app does not wake." end require './schedule' #ここで通常のアプリ(ただしjoinしてないもの)を読み込む use Rack::Auth::Basic do |username, password| username == ENV['BASIC_AUTH_USERNAME'] && password == ENV['BASIC_AUTH_PASSWORD'] end run HerokuAlternate.new # rackup config.ru -p 4567 -s webrick
相手からの通信(アクセス)を /update だけにしていますが、その他へのアクセスで機能を追加したい場合には case 節に追加してください。
schedule.rb
Herokuのappを二つ使って交互起動で常時運用(Sinatra版) - 別館 子子子子子子(ねこのここねこ)
と同じなので略します。
Procfile
web: bundle exec rackup config.ru -p $PORT
参考
- 橋本商会 » SinatraっぽいWAFを作る、46行で の[Rackアプリ最小構成]あたり
- callの返り値とRack::Response.newの引数の順序 - There's an echo in my head
- 「パーフェクト Ruby」第16章
(devise を知るにはまず warden を知るが良い - vimtaku blog の Application#call が「パーフェクト Ruby」第16章での Rack アプリケーションの解説に使われたスクリプトと同じ)
Heroku 24x7 対策 個人的変更手順:
- 相手側 app を Heroku に作成(app 名は testapp に対して testapp2 など単純に&リモートレポジトリ名は heroku2 に)
$ heroku create testapp2 --remote heroku2 $ heroku config:set TZ=Asia/Tokyo --remote heroku2 $ heroku addons:create papertrail --remote heroku2 (また papertrail 管理画面で Timezone を GMT+09:00 に)
-
- 各種環境定数を元の app (
heroku config --remote heroku
の出力結果)と同様に設定(heroku config:set …
)
- 各種環境定数を元の app (
- config.ru 新規作成
- Gemfile 変更
gem 'rack'
を追加bundle update
実行
- Procfile 変更
web: bundle exec rackup config.ru -p $PORT
に変更
- 各種環境定数設定
- BASIC_AUTH_USERNAME
- BASIC_AUTH_PASSWORD
- ANOTHER_SITE_URL(それぞれ適切に:https://testapp2.herokuapp.com/update )
- MY_SITE_WAKE_URL(それぞれ適切に:https://testapp.herokuapp.com/ )
$ heroku config:set BASIC_AUTH_USERNAME=username BASIC_AUTH_PASSWORD=password ANOTHER_SITE_URL=https://testapp2.herokuapp.com/update MY_SITE_WAKE_URL=https://testapp.herokuapp.com/ --remote heroku $ heroku config:set BASIC_AUTH_USERNAME=username BASIC_AUTH_PASSWORD=password ANOTHER_SITE_URL=https://testapp.herokuapp.com/update MY_SITE_WAKE_URL=https://testapp2.herokuapp.com/ --remote heroku2
- 元のスクリプトを変更
- join 削除
- 自己サイトへの定期アクセス追加
require 'rufus-scheduler' require 'open-uri' : scheduler = Rufus::Scheduler.new scheduler.every '15m' do begin open(ENV['MY_SITE_WAKE_URL']).read rescue OpenURI::HTTPError => ex puts 'wake up access.' end end
-
- 相手側 app からアクセスを受けたら
$update
がtrue
になるので、各定期作業(scheduler.cron
)節の冒頭に次を追加
- 相手側 app からアクセスを受けたら
scheduler.cron '…' do next if $update
git commit
するgit push heroku master && git push heroku2 master