Skip to content

Commit

Permalink
use sidekiq to do long-running stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Arie committed Feb 7, 2014
1 parent 162b615 commit 954b3ce
Show file tree
Hide file tree
Showing 21 changed files with 242 additions and 121 deletions.
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -25,6 +25,7 @@ gem 'cronic'
gem "google_visualr"
gem 'rack-cache'
gem 'paypal-sdk-rest'
gem 'sidekiq'

group :development do
gem 'better_errors'
Expand Down
14 changes: 14 additions & 0 deletions Gemfile.lock
Expand Up @@ -76,6 +76,8 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
celluloid (0.15.2)
timers (~> 1.1.0)
childprocess (0.4.0)
ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2)
Expand All @@ -94,6 +96,7 @@ GEM
sass (~> 3.1)
compass-rails (1.1.3)
compass (>= 0.12.2)
connection_pool (1.2.0)
coveralls (0.7.0)
multi_json (~> 1.3)
rest-client
Expand Down Expand Up @@ -250,6 +253,9 @@ GEM
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.1.1)
redis (3.0.7)
redis-namespace (1.4.1)
redis (~> 3.0.4)
ref (1.0.5)
request_store (1.0.5)
rest-client (1.6.7)
Expand Down Expand Up @@ -295,6 +301,12 @@ GEM
uuidtools
shoulda-matchers (2.5.0)
activesupport (>= 3.0.0)
sidekiq (2.17.4)
celluloid (>= 0.15.2)
connection_pool (>= 1.0.0)
json
redis (>= 3.0.6)
redis-namespace (>= 1.3.1)
simple_form (3.0.1)
actionpack (>= 4.0.0, < 4.1)
activemodel (>= 4.0.0, < 4.1)
Expand Down Expand Up @@ -327,6 +339,7 @@ GEM
thread_safe (0.1.3)
atomic
tilt (1.4.1)
timers (1.1.0)
tins (0.13.2)
treetop (1.4.15)
polyglot
Expand Down Expand Up @@ -407,6 +420,7 @@ DEPENDENCIES
selenium-webdriver
sentry-raven
shoulda-matchers
sidekiq
simple_form
steam-condenser!
sys-proctable
Expand Down
1 change: 1 addition & 0 deletions app/controllers/reservations_controller.rb
Expand Up @@ -32,6 +32,7 @@ def create
if @reservation.save
if @reservation.now?
@reservation.update_attribute(:start_instantly, true)
@reservation.start_reservation
flash[:notice] = "Reservation created for #{@reservation.server_name}. The server is now being configured, give it a minute to (re)boot/update and <a href='#{@reservation.server_connect_url}'>click here to join</a> or enter in console: #{@reservation.connect_string}".html_safe
redirect_to reservation_path(@reservation)
else
Expand Down
1 change: 1 addition & 0 deletions app/helpers/reservations_helper.rb
Expand Up @@ -58,6 +58,7 @@ def cancel_reservation

def end_reservation
reservation.update_attribute(:end_instantly, true)
reservation.end_reservation
link = "/uploads/#{reservation.zipfile_name}"
flash[:notice] = "Reservation removed, restarting server. Your STV demos and logs will be available <a href='#{link}' target=_blank>here</a> shortly".html_safe
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/reservation.rb
@@ -1,7 +1,7 @@
class Reservation < ActiveRecord::Base
attr_accessible :server, :user, :server_id, :user_id, :password, :rcon, :tv_password, :tv_relaypassword, :starts_at, :disable_source_tv,
:ends_at, :provisioned, :ended, :server_config, :server_config_id, :whitelist, :whitelist_id, :inactive_minute_counter,
:first_map, :start_instantly, :custom_whitelist_id
:first_map, :custom_whitelist_id
belongs_to :user
belongs_to :server
belongs_to :server_config
Expand Down
27 changes: 1 addition & 26 deletions app/services/reservation_manager.rb
Expand Up @@ -19,33 +19,8 @@ def update_reservation
manage_reservation(:update)
end

def after_start_reservation_steps
reservation.provisioned = true
reservation.save(:validate => false)
end

def after_update_reservation_steps
reservation.inactive_minute_counter = 0
reservation.save(:validate => false)
end

def after_end_reservation_steps
reservation.ends_at = Time.current
reservation.ended = true
reservation.duration = reservation.ends_at.to_i - reservation.starts_at.to_i
reservation.save(:validate => false)
end

def manage_reservation(action)
begin
server.send("#{action}_reservation", reservation)
rescue Exception => exception
Rails.logger.error "Something went wrong #{action}-ing the server for reservation #{reservation.id} - #{exception}"
Raven.capture_exception(exception) if Rails.env.production?
ensure
send("after_#{action}_reservation_steps")
Rails.logger.info "[#{Time.now}] #{action.capitalize}ed reservation: #{reservation.id} #{reservation}"
end
ReservationWorker.perform_async(reservation.id, action.to_s)
end
end

9 changes: 9 additions & 0 deletions app/workers/active_reservation_checker_worker.rb
@@ -0,0 +1,9 @@
class ActiveReservationCheckerWorker
include Sidekiq::Worker

def perform(reservation_ids)
reservation_ids.each do |reservation_id|
ServerNumberOfPlayersWorker.perform_async(reservation_id)
end
end
end
37 changes: 37 additions & 0 deletions app/workers/reservation_worker.rb
@@ -0,0 +1,37 @@
class ReservationWorker
include Sidekiq::Worker

attr_accessor :reservation

def perform(reservation_id, action)
begin
@reservation = Reservation.find(reservation_id)
server = reservation.server
server.send("#{action}_reservation", reservation)
rescue Exception => exception
Rails.logger.error "Something went wrong #{action}-ing the server for reservation #{reservation.id} - #{exception}"
Raven.capture_exception(exception) if Rails.env.production?
ensure
send("after_#{action}_reservation_steps")
Rails.logger.info "[#{Time.now}] #{action.capitalize}ed reservation: #{reservation.id} #{reservation}"
end
end

def after_start_reservation_steps
reservation.provisioned = true
reservation.save(:validate => false)
end

def after_update_reservation_steps
reservation.inactive_minute_counter = 0
reservation.save(:validate => false)
end

def after_end_reservation_steps
reservation.ends_at = Time.current
reservation.ended = true
reservation.duration = reservation.ends_at.to_i - reservation.starts_at.to_i
reservation.save(:validate => false)
end

end
18 changes: 18 additions & 0 deletions app/workers/server_number_of_players_worker.rb
@@ -0,0 +1,18 @@
class ServerNumberOfPlayersWorker
include Sidekiq::Worker

def perform(reservation_id)
reservation = Reservation.find(reservation_id)
if reservation.server.occupied?
reservation.update_column(:last_number_of_players, reservation.server.number_of_players)
reservation.update_column(:inactive_minute_counter, 0)
reservation.warn_nearly_over if reservation.nearly_over?
else
reservation.update_column(:last_number_of_players, 0)
reservation.increment!(:inactive_minute_counter)
if reservation.inactive_too_long?
reservation.end_reservation
end
end
end
end
1 change: 1 addition & 0 deletions config/application.rb
Expand Up @@ -17,6 +17,7 @@ class Application < Rails::Application

# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/app/services)
config.autoload_paths += %W(#{config.root}/app/workers)

# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
Expand Down
35 changes: 3 additions & 32 deletions config/cronic.d/serveme.rb
@@ -1,9 +1,7 @@
every '1s', :mutex => 'reservations' do
db do
start_instant_reservations
end_past_instant_reservations
if (Time.now.to_i) % 60 == 0
end_past_normal_reservations
end_past_reservations
start_active_reservations
check_active_reservations
end
Expand All @@ -21,7 +19,7 @@ def db(&block)
end
end

def end_past_normal_reservations
def end_past_reservations
unended_past_normal_reservations.map do |reservation|
reservation.end_reservation
end
Expand All @@ -35,16 +33,6 @@ def unended_past_reservations
Reservation.where('ends_at < ? AND provisioned = ? AND ended = ?', Time.current, true, false)
end

def end_past_instant_reservations
unended_past_instant_reservations.map do |reservation|
reservation.end_reservation
end
end

def unended_past_instant_reservations
Reservation.where('provisioned = ? AND ended = ? AND end_instantly = ?', true, false, true)
end

def end_reservation(reservations)
reservations.map do |reservation|
reservation.end_reservation
Expand All @@ -56,11 +44,6 @@ def start_active_reservations
start_reservations(unstarted_now_reservations)
end

def start_instant_reservations
unstarted_instant_reservations = now_reservations.where('provisioned = ? AND start_instantly = ?', false, true)
start_reservations(unstarted_instant_reservations)
end

def now_reservations
Reservation.current
end
Expand All @@ -74,17 +57,5 @@ def start_reservations(reservations)
def check_active_reservations
unended_now_reservations = now_reservations.where('ended = ?', false)
provisioned_now_reservations = unended_now_reservations.where('provisioned = ?', true)
provisioned_now_reservations.map do |reservation|
if reservation.server.occupied?
reservation.update_column(:last_number_of_players, reservation.server.number_of_players)
reservation.update_column(:inactive_minute_counter, 0)
reservation.warn_nearly_over if reservation.nearly_over?
else
reservation.update_column(:last_number_of_players, 0)
reservation.increment!(:inactive_minute_counter)
if reservation.inactive_too_long?
reservation.end_reservation
end
end
end
ActiveReservationCheckerWorker.perform_async(provisioned_now_reservations.map(&:id))
end
1 change: 1 addition & 0 deletions config/deploy.rb
@@ -1,6 +1,7 @@
require './config/boot'
require 'cronic/recipes'
require 'puma/capistrano'
require 'sidekiq/capistrano'

set :stages, %w(eu na)
set :default_stage, "eu"
Expand Down
1 change: 1 addition & 0 deletions config/deploy/eu.rb
Expand Up @@ -2,5 +2,6 @@
set :user, 'tf2'
set :puma_socket, 'tcp://127.0.0.1:3010'
set :puma_flags, '-w 4 -t 1:8'
set :sidekiq_processes, 2

server "#{main_server}", :web, :app, :db, :primary => true
1 change: 1 addition & 0 deletions config/deploy/na.rb
@@ -1,5 +1,6 @@
set :main_server, "na.fakkelbrigade.eu"
set :user, 'arie'
set :puma_flags, '-w 2 -t 1:8'
set :sidekiq_processes, 1

server "#{main_server}", :web, :app, :db, :primary => true
14 changes: 0 additions & 14 deletions features/step_definitions/reservations.rb
Expand Up @@ -117,18 +117,7 @@
click_button "Save"
end

Then "the server gets killed" do
LocalServer.any_instance.should_receive(:find_process_id).and_return { 12345 }
Process.should_receive(:kill).with(15, 12345)
end

Then "the server does not get killed" do
LocalServer.any_instance.should_not_receive(:find_process_id)
Process.should_not_receive(:kill)
end

When "I save the future reservation" do
step "the server does not get killed"
click_button "Save"
end

Expand All @@ -150,7 +139,6 @@
end

When "I cancel the future reservation" do
step "the server does not get killed"
@reservation = @current_user.reservations.last
within "#reservation_#{@reservation.id}" do
click_link "Cancel"
Expand Down Expand Up @@ -213,7 +201,6 @@
end

Given "I have a reservation that has just started" do
step "the server does not get killed"
start_reservation(Time.current)
end

Expand All @@ -234,7 +221,6 @@ def start_reservation(starts_at)
end

Given "the end reservations job has run" do
step "the server gets killed"
Reservation.last.end_reservation
end

Expand Down
3 changes: 3 additions & 0 deletions features/support/env.rb
Expand Up @@ -5,6 +5,9 @@

require 'cucumber/rails'
require 'cucumber/rspec/doubles'
require 'sidekiq'
require 'sidekiq/testing'
Sidekiq::Testing.inline!

#Load seed data
require Rails.root.join('db', 'seeds')
Expand Down

0 comments on commit 954b3ce

Please sign in to comment.