Last active
August 23, 2022 11:54
-
-
Save shikendon/22d4dc9a3821a924898fd7de2b7fa56a to your computer and use it in GitHub Desktop.
heroku.rake for CrowdTrail https://www.slideshare.net/shikendon/crawler-from-zero
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "heroku-api" | |
# heroku = Heroku::API.new(:api_key => API_KEY) # use API Key | |
# heroku = Heroku::API.new(:username => USERNAME, :password => PASSWORD) # use username and password | |
# heroku = Heroku::API.new(:headers => {'User-Agent' => 'custom'}) # use custom header | |
# NOTE: You can leave out the :api_key if ENV['HEROKU_API_KEY'] is set instead. | |
# https://github.com/heroku/heroku.rb | |
namespace :heroku do | |
namespace :webs do | |
desc "Restarts all Heroku webs" | |
task :restart do | |
heroku = Heroku::API.new | |
response = heroku.get_ps(ENV["HEROKU_APP_NAME"]) | |
webs = response.body.select { |item| item["process"] =~ /web/ } | |
webs.each do |web| | |
process = web["process"] | |
pretty_state = web["pretty_state"] | |
puts "Restarting #{process} (#{pretty_state}) . . ." | |
heroku.post_ps_restart(ENV["HEROKU_APP_NAME"], "ps" => process) | |
end | |
end | |
end | |
namespace :workers do | |
desc "Restarts all Heroku workers" | |
task :restart do | |
heroku = Heroku::API.new | |
response = heroku.get_ps(ENV["HEROKU_APP_NAME"]) | |
workers = response.body.select { |item| item["process"] =~ /worker/ } | |
workers.each do |worker| | |
process = worker["process"] | |
pretty_state = worker["pretty_state"] | |
puts "Restarting #{process} (#{pretty_state}) . . ." | |
heroku.post_ps_restart(ENV["HEROKU_APP_NAME"], "ps" => process) | |
end | |
end | |
desc "Restarts the Heroku worker that matches the rules" | |
task :try_restart, [:max_running_time] do |_t, args| | |
args.with_defaults(max_running_time: 600) | |
heroku = Heroku::API.new | |
response = heroku.get_ps(ENV["HEROKU_APP_NAME"]) | |
workers = response.body.select { |item| item["process"] =~ /worker/ } | |
workers.each do |worker| | |
process = worker["process"] | |
elapsed = worker["elapsed"] # Seconds | |
pretty_state = worker["pretty_state"] | |
next if elapsed < args[:max_running_time] | |
puts "Restarting #{process} (#{pretty_state}) . . ." | |
heroku.post_ps_restart(ENV["HEROKU_APP_NAME"], "ps" => process) | |
break | |
end | |
end | |
desc "Auto scaling the Heroku workers count according to Sidekiq jobs count" | |
task :auto_scaling, [:WORKER_NAME] => :environment do |_t, args| | |
args.with_defaults(WORKER_NAME: "worker") | |
APP_NAME = ENV["HEROKU_APP_NAME"] | |
WORKER_NAME = args[:WORKER_NAME] | |
heroku = Heroku::API.new | |
queues = Sidekiq::Queue.all # 所有 Sidekiq 佇列名稱物件 | |
queues_size = queues.map { |queue| Sidekiq::Queue.new(queue.name).size }.inject(0, :+) # 剩餘任務數量 | |
# 平均一個 2X dyno 每分鐘可以處理 600 個 jobs | |
# 目前設定每個小時 50 分的時候會重新檢查一次有無尚未 parse 的 project_log | |
# 因此所有 jobs 都必須在 45 分以前完成否則會影響到下一個小時的任務效能 | |
now_minutes = Time.now.strftime("%M").to_i # 目前分鐘 | |
left_minutes = now_minutes.between?(0, 45) ? 45 - now_minutes : 0 # 剩餘分鐘 | |
workers_size = queues_size / 500 / [left_minutes, 1].max # 剩餘任務數量 / 處理速度 / 剩餘分鐘 | |
workers_size = 1 if workers_size < 1 # 最少開一個 worker | |
workers_size = 10 if workers_size > 10 # 最多開 10 個 worker | |
puts "Scaling #{WORKER_NAME} dyno count to #{workers_size}" | |
heroku.post_ps_scale(APP_NAME, WORKER_NAME, workers_size) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment