toro 0.0.1 → 0.0.2
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.
- data/README.md +531 -0
- data/lib/generators/toro/install/install_generator.rb +25 -0
- data/lib/generators/toro/install/templates/create_toro_jobs.rb +9 -0
- data/lib/tasks/tasks.rb +19 -0
- data/lib/toro.rb +51 -1
- data/lib/toro/actor.rb +8 -0
- data/lib/toro/actor_manager.rb +11 -0
- data/lib/toro/cli.rb +87 -0
- data/lib/toro/client.rb +17 -0
- data/lib/toro/database.rb +38 -0
- data/lib/toro/fetcher.rb +40 -0
- data/lib/toro/job.rb +38 -0
- data/lib/toro/listener.rb +44 -0
- data/lib/toro/logging.rb +80 -0
- data/lib/toro/manager.rb +143 -0
- data/lib/toro/middleware/chain.rb +81 -0
- data/lib/toro/middleware/server/error.rb +19 -0
- data/lib/toro/middleware/server/error_storage.rb +22 -0
- data/lib/toro/middleware/server/properties.rb +15 -0
- data/lib/toro/middleware/server/retry.rb +25 -0
- data/lib/toro/monitor.rb +34 -0
- data/lib/toro/monitor/custom_views.rb +26 -0
- data/lib/toro/monitor/engine.rb +11 -0
- data/lib/toro/monitor/time_formatter.rb +27 -0
- data/lib/toro/processor.rb +48 -0
- data/lib/toro/railtie.rb +9 -0
- data/lib/toro/sql/down.sql +4 -0
- data/lib/toro/sql/up.sql +68 -0
- data/lib/toro/version.rb +1 -1
- data/lib/toro/worker.rb +44 -0
- metadata +49 -22
    
        data/lib/toro/manager.rb
    ADDED
    
    | @@ -0,0 +1,143 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              class Shutdown < Interrupt; end
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class Manager
         | 
| 5 | 
            +
                include Actor
         | 
| 6 | 
            +
                include ActorManager
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                attr_reader :busy, :ready
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def initialize(options={})
         | 
| 11 | 
            +
                  defaults = {
         | 
| 12 | 
            +
                    concurrency: 1,
         | 
| 13 | 
            +
                    queues: [Toro.options[:default_queue]],
         | 
| 14 | 
            +
                  }
         | 
| 15 | 
            +
                  options = defaults.merge(options)
         | 
| 16 | 
            +
                  @queues = options[:queues]
         | 
| 17 | 
            +
                  @threads = {}
         | 
| 18 | 
            +
                  @ready = options[:concurrency].times.map do
         | 
| 19 | 
            +
                    processor = Processor.new_link(current_actor)
         | 
| 20 | 
            +
                    processor.proxy_id = processor.object_id
         | 
| 21 | 
            +
                    processor
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                  @busy = []
         | 
| 24 | 
            +
                  @is_done = false
         | 
| 25 | 
            +
                  @fetcher = Fetcher.new({ manager: current_actor, queues: options[:queues] })
         | 
| 26 | 
            +
                  @listener = Listener.new({ queues: @queues, fetcher: @fetcher, manager: current_actor })
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def start
         | 
| 30 | 
            +
                  @is_done = false
         | 
| 31 | 
            +
                  @listener.async.start
         | 
| 32 | 
            +
                  @ready.each { dispatch }
         | 
| 33 | 
            +
                  heartbeat
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def stop
         | 
| 37 | 
            +
                  @is_done = true
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  Toro.logger.debug "Shutting down #{@ready.size} quiet workers"
         | 
| 40 | 
            +
                  @ready.each { |processor| processor.terminate if processor.alive? }
         | 
| 41 | 
            +
                  @ready.clear
         | 
| 42 | 
            +
                  @fetcher.terminate if @fetcher.alive?
         | 
| 43 | 
            +
                  if @listener.alive?
         | 
| 44 | 
            +
                    actors[:listener].stop if actors[:listener]
         | 
| 45 | 
            +
                    @listener.terminate
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                  return if clean_up_for_graceful_shutdown
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  hard_shutdown_in(Toro.options[:hard_shutdown_time])
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def assign(job)
         | 
| 53 | 
            +
                  raise 'No processors ready' if !is_ready?
         | 
| 54 | 
            +
                  processor = @ready.pop
         | 
| 55 | 
            +
                  @busy << processor
         | 
| 56 | 
            +
                  processor.async.process(job)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def is_ready?
         | 
| 60 | 
            +
                  !@ready.empty?
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def dispatch
         | 
| 64 | 
            +
                  raise "No processors, cannot continue!" if @ready.empty? && @busy.empty?
         | 
| 65 | 
            +
                  raise "No ready processor!?" if @ready.empty?
         | 
| 66 | 
            +
                  @fetcher.async.fetch
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def clean_up_for_graceful_shutdown
         | 
| 70 | 
            +
                  if @busy.empty?
         | 
| 71 | 
            +
                    shutdown
         | 
| 72 | 
            +
                    return true
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  after(Toro.options[:graceful_shutdown_time]) { clean_up_for_graceful_shutdown }
         | 
| 76 | 
            +
                  false
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def hard_shutdown_in(delay)
         | 
| 80 | 
            +
                  Toro.logger.info "Pausing up to #{delay} seconds to allow workers to finish..."
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  after(delay) do
         | 
| 83 | 
            +
                    # We've reached the timeout and we still have busy processors.
         | 
| 84 | 
            +
                    # They must die but their messages shall live on.
         | 
| 85 | 
            +
                    Toro.logger.warn "Terminating #{@busy.size} busy worker threads"
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    requeue
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    @busy.each do |processor|
         | 
| 90 | 
            +
                      if processor.alive? && thread = @threads.delete(processor.object_id)
         | 
| 91 | 
            +
                        thread.raise Shutdown
         | 
| 92 | 
            +
                      end
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    signal_shutdown
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                def shutdown
         | 
| 100 | 
            +
                  requeue
         | 
| 101 | 
            +
                  signal_shutdown
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                def requeue
         | 
| 105 | 
            +
                  Toro::Database.with_connection do
         | 
| 106 | 
            +
                    Job.where(status: 'running', started_by: Toro.process_identity).
         | 
| 107 | 
            +
                      update_all(status: 'queued', started_by: nil, started_at: nil)
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                def signal_shutdown
         | 
| 112 | 
            +
                  after(0) { signal(:shutdown) }
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                def set_thread(proxy_id, thread)
         | 
| 116 | 
            +
                  @threads[proxy_id] = thread
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                def heartbeat
         | 
| 120 | 
            +
                  return if stopped?
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  after(5) do
         | 
| 123 | 
            +
                    heartbeat
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def processor_complete(processor)
         | 
| 128 | 
            +
                  @threads.delete(processor.object_id)
         | 
| 129 | 
            +
                  @busy.delete(processor)
         | 
| 130 | 
            +
                  if stopped?
         | 
| 131 | 
            +
                    processor.terminate if processor.alive?
         | 
| 132 | 
            +
                    shutdown if @busy.empty?
         | 
| 133 | 
            +
                  else
         | 
| 134 | 
            +
                    @ready << processor if processor.alive?
         | 
| 135 | 
            +
                    dispatch
         | 
| 136 | 
            +
                  end
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                def stopped?
         | 
| 140 | 
            +
                  @is_done
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                class Chain
         | 
| 4 | 
            +
                  include Enumerable
         | 
| 5 | 
            +
                  attr_reader :entries
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def initialize_copy(copy)
         | 
| 8 | 
            +
                    copy.instance_variable_set(:@entries, entries.dup)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def each(&block)
         | 
| 12 | 
            +
                    entries.each(&block)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def initialize
         | 
| 16 | 
            +
                    @entries = []
         | 
| 17 | 
            +
                    yield self if block_given?
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def remove(klass)
         | 
| 21 | 
            +
                    entries.delete_if { |entry| entry.klass == klass }
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def add(klass, *args)
         | 
| 25 | 
            +
                    remove(klass) if exists?(klass)
         | 
| 26 | 
            +
                    entries << Entry.new(klass, *args)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def insert_before(oldklass, newklass, *args)
         | 
| 30 | 
            +
                    i = entries.index { |entry| entry.klass == newklass }
         | 
| 31 | 
            +
                    new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
         | 
| 32 | 
            +
                    i = entries.index { |entry| entry.klass == oldklass } || 0
         | 
| 33 | 
            +
                    entries.insert(i, new_entry)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def insert_after(oldklass, newklass, *args)
         | 
| 37 | 
            +
                    i = entries.index { |entry| entry.klass == newklass }
         | 
| 38 | 
            +
                    new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
         | 
| 39 | 
            +
                    i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
         | 
| 40 | 
            +
                    entries.insert(i+1, new_entry)
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def exists?(klass)
         | 
| 44 | 
            +
                    any? { |entry| entry.klass == klass }
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def retrieve
         | 
| 48 | 
            +
                    map(&:make_new)
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def clear
         | 
| 52 | 
            +
                    entries.clear
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def invoke(*args, &final_action)
         | 
| 56 | 
            +
                    chain = retrieve.dup
         | 
| 57 | 
            +
                    traverse_chain = lambda do
         | 
| 58 | 
            +
                      if chain.empty?
         | 
| 59 | 
            +
                        final_action.call
         | 
| 60 | 
            +
                      else
         | 
| 61 | 
            +
                        chain.shift.call(*args, &traverse_chain)
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                    traverse_chain.call
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                class Entry
         | 
| 69 | 
            +
                  attr_reader :klass
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def initialize(klass, *args)
         | 
| 72 | 
            +
                    @klass = klass
         | 
| 73 | 
            +
                    @args  = args
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  def make_new
         | 
| 77 | 
            +
                    @klass.new(*@args)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                module Server
         | 
| 4 | 
            +
                  class Error
         | 
| 5 | 
            +
                    def call(job, worker)
         | 
| 6 | 
            +
                      begin
         | 
| 7 | 
            +
                        yield
         | 
| 8 | 
            +
                      rescue Exception => exception
         | 
| 9 | 
            +
                        job.update_attributes(
         | 
| 10 | 
            +
                          status: 'failed',
         | 
| 11 | 
            +
                          finished_at: Time.now
         | 
| 12 | 
            +
                        )
         | 
| 13 | 
            +
                        raise exception
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                module Server
         | 
| 4 | 
            +
                  class ErrorStorage
         | 
| 5 | 
            +
                    def call(job, worker)
         | 
| 6 | 
            +
                      begin
         | 
| 7 | 
            +
                        yield
         | 
| 8 | 
            +
                      rescue Exception => exception
         | 
| 9 | 
            +
                        job.reload
         | 
| 10 | 
            +
                        job.set_properties(
         | 
| 11 | 
            +
                          'error:class' => exception.class.name,
         | 
| 12 | 
            +
                          'error:message' => exception.message,
         | 
| 13 | 
            +
                          'error:backtrace' => exception.backtrace
         | 
| 14 | 
            +
                        )
         | 
| 15 | 
            +
                        job.save
         | 
| 16 | 
            +
                        raise exception
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                module Server
         | 
| 4 | 
            +
                  class Properties
         | 
| 5 | 
            +
                    def call(job, worker)
         | 
| 6 | 
            +
                      result = yield
         | 
| 7 | 
            +
                      if result.is_a?(Hash) && result[:job_properties].is_a?(Hash)
         | 
| 8 | 
            +
                        job.set_properties(result[:job_properties])
         | 
| 9 | 
            +
                        job.save
         | 
| 10 | 
            +
                      end
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                module Server
         | 
| 4 | 
            +
                  class Retry
         | 
| 5 | 
            +
                    def call(job, worker)
         | 
| 6 | 
            +
                      begin
         | 
| 7 | 
            +
                        yield
         | 
| 8 | 
            +
                      rescue Exception => exception
         | 
| 9 | 
            +
                        if worker.toro_options[:retry_interval]
         | 
| 10 | 
            +
                          interval = worker.toro_options[:retry_interval]
         | 
| 11 | 
            +
                          job.reload
         | 
| 12 | 
            +
                          job.properties ||= {}
         | 
| 13 | 
            +
                          job.properties['retry:errors'] ||= []
         | 
| 14 | 
            +
                          job.properties['retry:errors'] << "#{exception.class.name} -- #{exception.message} -- #{Time.now}"
         | 
| 15 | 
            +
                          job.status = 'scheduled'
         | 
| 16 | 
            +
                          job.scheduled_at = Time.now + interval
         | 
| 17 | 
            +
                          job.save
         | 
| 18 | 
            +
                        end
         | 
| 19 | 
            +
                        raise exception
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
    
        data/lib/toro/monitor.rb
    ADDED
    
    | @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            require 'slim'
         | 
| 2 | 
            +
            require 'jquery-datatables-rails'
         | 
| 3 | 
            +
            require 'rails-datatables'
         | 
| 4 | 
            +
            require 'action_view'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            directory = File.dirname(File.absolute_path(__FILE__))
         | 
| 7 | 
            +
            require "#{directory}/monitor/custom_views.rb"
         | 
| 8 | 
            +
            require "#{directory}/monitor/time_formatter.rb"
         | 
| 9 | 
            +
            require "#{directory}/monitor/engine.rb" if defined?(Rails)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            module Toro
         | 
| 12 | 
            +
              module Monitor
         | 
| 13 | 
            +
                DEFAULTS = {
         | 
| 14 | 
            +
                  :charts => nil,
         | 
| 15 | 
            +
                  :javascripts => [],
         | 
| 16 | 
            +
                  :poll_interval => 3000
         | 
| 17 | 
            +
                }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                class << self
         | 
| 20 | 
            +
                  def options
         | 
| 21 | 
            +
                    @options ||= DEFAULTS.dup
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def options=(options)
         | 
| 25 | 
            +
                    @options = options
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def root_path
         | 
| 29 | 
            +
                    toro_monitor_path = Toro::Monitor::Engine.routes.url_helpers.toro_monitor_path
         | 
| 30 | 
            +
                    "#{::Rails.application.config.relative_url_root}#{toro_monitor_path}"
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Monitor
         | 
| 3 | 
            +
                class CustomViews
         | 
| 4 | 
            +
                  @views = []
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  class << self
         | 
| 7 | 
            +
                    def add(name, path, &block)
         | 
| 8 | 
            +
                      @views << {
         | 
| 9 | 
            +
                        name: name,
         | 
| 10 | 
            +
                        path: path,
         | 
| 11 | 
            +
                        filter: block
         | 
| 12 | 
            +
                      }
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def for_job(job)
         | 
| 16 | 
            +
                      views = []
         | 
| 17 | 
            +
                      @views.each do |view|
         | 
| 18 | 
            +
                        is_valid = view[:filter].call(job)
         | 
| 19 | 
            +
                        views << view.dup if is_valid
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                      views
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              module Monitor
         | 
| 3 | 
            +
                class TimeFormatter
         | 
| 4 | 
            +
                  class << self
         | 
| 5 | 
            +
                    include ActionView::Helpers::DateHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def distance_of_time(from_time, to_time)
         | 
| 8 | 
            +
                      replacements = {
         | 
| 9 | 
            +
                        'less than ' => '',
         | 
| 10 | 
            +
                        'about ' => '',
         | 
| 11 | 
            +
                        ' days' => 'd',
         | 
| 12 | 
            +
                        ' day' => 'd',
         | 
| 13 | 
            +
                        ' hours' => 'h',
         | 
| 14 | 
            +
                        ' hour' => 'h',
         | 
| 15 | 
            +
                        ' minutes' => 'm',
         | 
| 16 | 
            +
                        ' minute' => 'm',
         | 
| 17 | 
            +
                        ' seconds' => 's',
         | 
| 18 | 
            +
                        ' second' => 's'
         | 
| 19 | 
            +
                      }
         | 
| 20 | 
            +
                      phrase = distance_of_time_in_words(from_time, to_time, include_seconds: true)
         | 
| 21 | 
            +
                      replacements.each { |from, to| phrase.gsub!(from, to) }
         | 
| 22 | 
            +
                      phrase
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            module Toro
         | 
| 2 | 
            +
              class Processor
         | 
| 3 | 
            +
                include Actor
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                attr_accessor :proxy_id
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class << self
         | 
| 8 | 
            +
                  def default_middleware
         | 
| 9 | 
            +
                    Middleware::Chain.new do |middleware|
         | 
| 10 | 
            +
                      middleware.add Middleware::Server::Properties
         | 
| 11 | 
            +
                      middleware.add Middleware::Server::Retry
         | 
| 12 | 
            +
                      middleware.add Middleware::Server::ErrorStorage
         | 
| 13 | 
            +
                      middleware.add Middleware::Server::Error
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def initialize(manager)
         | 
| 19 | 
            +
                  @manager = manager
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def process(job)
         | 
| 23 | 
            +
                  @manager.set_thread(proxy_id, Thread.current)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  Toro.logger.info "Processing #{job}"
         | 
| 26 | 
            +
                  worker = job.class_name.constantize
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  Toro::Database.with_connection do
         | 
| 29 | 
            +
                    begin
         | 
| 30 | 
            +
                      Toro.server_middleware.invoke(job, worker) do
         | 
| 31 | 
            +
                        worker.new.perform(*job.args)
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
                    rescue Exception => exception
         | 
| 34 | 
            +
                      Toro.logger.error "#{exception.class}: #{exception.message}"
         | 
| 35 | 
            +
                      Toro.logger.error exception.backtrace.join("\n")
         | 
| 36 | 
            +
                    else
         | 
| 37 | 
            +
                      Toro.logger.info "Processed #{job}"
         | 
| 38 | 
            +
                      job.update_attributes(
         | 
| 39 | 
            +
                        status: 'complete',
         | 
| 40 | 
            +
                        finished_at: Time.now
         | 
| 41 | 
            +
                      )
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  
         | 
| 45 | 
            +
                  @manager.processor_complete(current_actor) if @manager.alive?
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         |