Changeset af8813eb9aca5c38c2d1715935d0917036042d5c
Dimitrij Denissenko
Dimitrij Denissenko
over 1 year ago

Changeset af8813e

Improved TaskRunner, changed config storage frmo YAML to DB

Affected files:

  • Added db/migrate/20090419112736_create_tasks.rb
  • Added lib/retrospectiva/task_manager.rb
  • Added lib/retrospectiva/task_manager/parser.rb
  • Added lib/retrospectiva/task_manager/task.rb
  • Deleted config/runtime/tasks.yml.default
  • Deleted lib/retrospectiva/tasks.rb
  • Updated app/controllers/admin/tasks_controller.rb (Quick Diff)

    app/controllers/admin/tasks_controller.rb

    841111faf8813e
    1
    #--
    1
    #--
    2
    # Copyright (C) 2008 Dimitrij Denissenko
    2
    # Copyright (C) 2009 Dimitrij Denissenko
    3
    # Please read LICENSE document for more information.
    3
    # Please read LICENSE document for more information.
    4
    #++
    4
    #++
    5
    class Admin::TasksController < AdminAreaController
    5
    class Admin::TasksController < AdminAreaController
    6
      verify :params => :tasks, :only => :save
    6
      verify :params => :tasks, :only => :save
    7
    7
    8
      def index
    8
      def index
    9
        @tasks  = Retrospectiva::Tasks.tasks
    9
        @tasks = Retrospectiva::TaskManager::Parser.new.tasks
    10
      end
    10
      end
    11
      
    11
      
    12
      def save
    12
      def save
    13
        configuration = params[:tasks].inject({}) do |result, (name, interval)|
    13
        params[:tasks].each do |name, interval|
    14
          seconds = TimeInterval.in_seconds(interval[:count], interval[:units]) rescue 0
    14
          seconds = TimeInterval.in_seconds(interval[:count], interval[:units]) rescue 0
    15
          result.merge name => seconds
    15
          Retrospectiva::TaskManager::Task.create_or_update(name, seconds)
    16
        end
    16
        end if params[:tasks].is_a?(Hash)
    17
        Retrospectiva::Tasks.update(configuration)
     
    18
        flash[:notice] = _('Task configuration was successfully updated.')
    17
        flash[:notice] = _('Task configuration was successfully updated.')
    19
        redirect_to admin_tasks_path
    18
        redirect_to admin_tasks_path
    20
      end  
    19
      end  
  • Updated app/models/queued_mail.rb (Quick Diff)

    app/models/queued_mail.rb

    66c1706af8813e
    1
    #--
    1
    #--
    2
    # Copyright (C) 2008 Dimitrij Denissenko
    2
    # Copyright (C) 2009 Dimitrij Denissenko
    3
    # Please read LICENSE document for more information.
    3
    # Please read LICENSE document for more information.
    4
    #++
    4
    #++
    5
    class QueuedMail < ActiveRecord::Base
    5
    class QueuedMail < ActiveRecord::Base
    ...
     
    ...
     
    9
      named_scope :pending, :conditions => ['delivered_at IS NULL'], :order => 'created_at'
    9
      named_scope :pending, :conditions => ['delivered_at IS NULL'], :order => 'created_at'
    10
      
    10
      
    11
      def mailer_class
    11
      def mailer_class
    12
        @mailer_class ||= mailer_class_name.constantize rescue nil
    12
        mailer_class_name.constantize rescue nil
    13
      end
    13
      end
    14
    14
    15
      def deliver!
    15
      def deliver!
    16
        mailer_class ? mailer_class.deliver(object) && deactivate! : false 
    16
        if mailer_class
     
    17
          mailer_class.deliver(object) 
     
    18
          deactivate!
     
    19
        else
     
    20
          false      
     
    21
        end
    17
      end
    22
      end
    18
      
    23
      
    19
      def deactivate!
    24
      def deactivate!
    20
        t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
    25
        update_attribute :delivered_at, Time.now.utc
    21
        update_attribute :delivered_at, t
     
    22
      end
    26
      end
    23
    27
    24
    end
    28
    end
  • Updated app/views/admin/tasks/_task.html.erb (Quick Diff)

    app/views/admin/tasks/_task.html.erb

    66c1706af8813e
    2
      <td class="strong"><%=h task.name.humanize %></td>
    2
      <td class="strong"><%=h task.name.humanize %></td>
    3
      <td><%=h task.description %></td>
    3
      <td><%=h task.description %></td>
    4
      <td>
    4
      <td>
    5
        <% if task.started -%>
    5
        <% if task.running? -%>
    6
          <%= _('Started') %> <%=h time_interval_in_words(task.started) %>
    6
          <%= _('Started') %> <%=h time_interval_in_words(task.started_at) %>
    7
        <% elsif task.last_run -%>
    7
        <% elsif task.finished_at > 1.year.ago -%>
    8
          <%= _('Last run') %> <%=h time_interval_in_words(task.last_run) %>
    8
          <%= _('Finished') %> <%=h time_interval_in_words(task.finished_at) %>
    9
        <% else -%>
    9
        <% else -%>
    10
          &ndash;
    10
          &ndash;
    11
        <% end -%>
    11
        <% end -%>
  • Updated config/environments/development.rb (Quick Diff)

    config/environments/development.rb

    66c1706af8813e
    14
    config.action_controller.perform_caching             = false
    14
    config.action_controller.perform_caching             = false
    15
    15
    16
    # Don't care if the mailer can't send
    16
    # Don't care if the mailer can't send
    17
    config.action_mailer.raise_delivery_errors = false
    17
    config.action_mailer.raise_delivery_errors = false
     
    18
    config.action_mailer.perform_deliveries = false
  • Updated db/default_content.rb (Quick Diff)

    db/default_content.rb

    de482d6af8813e
    32
            creator.create_group unless Group.exists?(:name => 'Default')
    32
            creator.create_group unless Group.exists?(:name => 'Default')
    33
            creator.create_public unless User.exists?(:name => 'Public')
    33
            creator.create_public unless User.exists?(:name => 'Public')
    34
            creator.create_admin unless User.exists?(:admin => true, :active => true)
    34
            creator.create_admin unless User.exists?(:admin => true, :active => true)
     
    35
            creator.create_tasks if Retrospectiva::TaskManager::Task.count.zero?
    35
          end
    36
          end
    36
        end
    37
        end
    37
    38
    ...
     
    ...
     
    49
          end
    50
          end
    50
        end
    51
        end
    51
    52
     
    53
        def create_tasks
     
    54
          puts 'Creating default tasks'
     
    55
          Retrospectiva::TaskManager::Task.create :name => 'sync_repositories', :interval => 600
     
    56
          Retrospectiva::TaskManager::Task.create :name => 'process_mails', :interval => 300
     
    57
        end
     
    58
    52
        def create_group
    59
        def create_group
    53
          puts 'Creating default group'
    60
          puts 'Creating default group'
    54
          Group.create!(:name => 'Default')
    61
          Group.create!(:name => 'Default')
  • Updated db/schema.core.rb (Quick Diff)

    db/schema.core.rb

    4f2ff01af8813e
    9
    #
    9
    #
    10
    # It's strongly recommended to check this file into your version control system.
    10
    # It's strongly recommended to check this file into your version control system.
    11
    11
    12
    ActiveRecord::Schema.define(:version => 20090124095048) do
    12
    ActiveRecord::Schema.define(:version => 20090419112736) do
    13
    13
    14
      create_table "attachments", :force => true do |t|
    14
      create_table "attachments", :force => true do |t|
    15
        t.string   "file_name"
    15
        t.string   "file_name"
    ...
     
    ...
     
    186
    186
    187
      add_index "tags", ["name"], :name => "i_tags_on_name"
    187
      add_index "tags", ["name"], :name => "i_tags_on_name"
    188
    188
     
    189
      create_table "tasks", :force => true do |t|
     
    190
        t.string   "name",        :limit => 60
     
    191
        t.datetime "started_at",                :default => '1970-01-01 00:00:00', :null => false
     
    192
        t.datetime "finished_at",               :default => '1970-01-01 00:00:00', :null => false
     
    193
        t.integer  "interval",                  :default => 0,                     :null => false
     
    194
      end
     
    195
     
    196
      add_index "tasks", ["name"], :name => "i_tasks_name"
     
    197
    189
      create_table "ticket_changes", :force => true do |t|
    198
      create_table "ticket_changes", :force => true do |t|
    190
        t.integer  "ticket_id"
    199
        t.integer  "ticket_id"
    191
        t.string   "author",     :limit => 75
    200
        t.string   "author",     :limit => 75
  • Updated lib/retrospectiva.rb (Quick Diff)

    lib/retrospectiva.rb

    66c1706af8813e
    1
    require 'retrospectiva/core_ext'
    1
    require 'retrospectiva/core_ext'
    2
    require 'retrospectiva/session'
    2
    require 'retrospectiva/session'
    3
    require 'retrospectiva/tasks'
     
    4
    require 'retrospectiva/misc'
    3
    require 'retrospectiva/misc'
    5
    4
    6
    require 'retrospectiva/extension_manager'
    5
    require 'retrospectiva/extension_manager'
    7
    require 'retrospectiva/configuration_manager'
    6
    require 'retrospectiva/configuration_manager'
    8
    require 'retrospectiva/access_manager'
    7
    require 'retrospectiva/access_manager'
    9
    require 'retrospectiva/previewable'
    8
    require 'retrospectiva/previewable'
     
    9
    require 'retrospectiva/task_manager'
  • Updated lib/tasks/rspec.rake (Quick Diff)

    lib/tasks/rspec.rake

    b9c19e3af8813e
    1
    gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9
     
    2
     
    3
    # Don't load rspec if running "rake gems:*"
    1
    # Don't load rspec if running "rake gems:*"
    4
    unless ARGV.any? {|a| a =~ /^gems/}
    2
    unless ARGV.any? {|a| a =~ /^gems/}
     
    3
      gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9
    5
    4
    6
    begin
    5
    begin
    7
      require 'spec/rake/spectask'
    6
      require 'spec/rake/spectask'
  • Updated script/retro_tasks (Quick Diff)

    script/retro_tasks

    66c1706af8813e
    1
    #!/usr/bin/env ruby
    1
    #!/usr/bin/env ruby
    2
    2
    3
    #--
    3
    require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'boot'))
    4
    # Copyright (C) 2007 Dimitrij Denissenko
     
    5
    # Please read LICENSE document for more information.
     
    6
    #++
     
    7
    4
     
    5
    require 'active_record'
     
    6
    require 'active_support'
     
    7
    require 'erb'
    8
    require 'yaml'
    8
    require 'yaml'
    9
    require 'logger'
     
    10
    9
    11
    class RetroTasks  
    10
    Time.zone_default = Time.__send__(:get_zone, 'UTC')         
    12
      
    11
    ActiveRecord::Base.time_zone_aware_attributes = true
    13
      def self.run
    12
    ActiveRecord::Base.default_timezone = :utc
    14
        new.run
     
    15
      end
     
    16
    13
    17
      attr_reader :logger
    14
    load 'retrospectiva/task_manager.rb'
    18
      
     
    19
      def initialize
     
    20
        @logger = Logger.new(log_file)
     
    21
        @logger.level = Logger::INFO
     
    22
      end
     
    23
    15
    24
      def run
    16
    manager = Retrospectiva::TaskManager.new
    25
        return if tasks_to_run.empty?
    17
    if ARGV.include?('tasks')
    26
        
    18
      puts "Tasks: " + manager.tasks.map(&:name).inspect
    27
        require 'rubygems'
    19
    elsif ARGV.include?('pending')
    28
        load File.join(RAILS_ROOT, 'Rakefile')
    20
      puts "Pending: " + manager.pending.map(&:name).inspect
    29
    21
    else 
    30
        tasks_to_run.each do |task_name|
    22
      manager.run
    31
          if task = Rake.application.lookup("retro:#{task_name}")
     
    32
            update_configuration(task_name, :started => current_minute)
     
    33
            begin
     
    34
              task.invoke
     
    35
            rescue Exception => ex
     
    36
              log_exception(ex)
     
    37
            ensure
     
    38
              update_configuration(task_name, :last_run => current_minute, :started => nil)
     
    39
            end
     
    40
          else
     
    41
            delete_configuration(task_name)
     
    42
          end
     
    43
        end  
     
    44
      end
     
    45
     
    46
      protected
     
    47
     
    48
        def config
     
    49
          file = File.exist?(config_file) ? config_file : "#{config_file}.default"
     
    50
          (YAML.load_file(file) rescue {}) || {}    
     
    51
        end
     
    52
     
    53
        def config_file
     
    54
          File.join(RAILS_ROOT, 'config', 'runtime', 'tasks.yml')  
     
    55
        end
     
    56
      
     
    57
        def log_file
     
    58
          File.join(RAILS_ROOT, 'log', 'tasks.log')  
     
    59
        end
     
    60
          
     
    61
        def log_exception(exception)
     
    62
          clean_trace = exception.backtrace.collect { |line| line.gsub(RAILS_ROOT, '') }
     
    63
          self.logger.fatal(
     
    64
            "\n\n#{exception.class} (#{exception.message}):\n    " +
     
    65
            clean_trace.join("\n    ") +
     
    66
            "\n\n"
     
    67
          )    
     
    68
        end
     
    69
        
     
    70
        def current_minute
     
    71
          time = Time.now.utc
     
    72
          time -= time.sec
     
    73
        end
     
    74
      
     
    75
        def tasks_to_run
     
    76
          @tasks_to_run ||= self.config.inject([]) do |result, (task, task_conf)|
     
    77
            if task_conf.is_a?(Hash)     
     
    78
              interval = Kernel.Integer(task_conf[:interval]) rescue 0       
     
    79
              if interval > 0 && !task_conf[:started]
     
    80
                last_run = task_conf[:last_run] || Time.at(0).utc
     
    81
                if (last_run + interval).to_i <= current_minute.to_i
     
    82
                  result << task
     
    83
                end    
     
    84
              end  
     
    85
            end  
     
    86
            result
     
    87
          end    
     
    88
        end
     
    89
     
    90
        def update_configuration(task_name, attributes)
     
    91
          retries = 0
     
    92
          begin	
     
    93
            task_conf = self.config[task_name].merge(attributes)
     
    94
            write_configuration( self.config.merge(task_name => task_conf) )
     
    95
          rescue
     
    96
            if (retries += 1) < 3
     
    97
              sleep 1
     
    98
              retry
     
    99
            else
     
    100
              raise
     
    101
            end
     
    102
          end
     
    103
        end  
     
    104
     
    105
        def delete_configuration(task_name)
     
    106
          write_configuration( self.config.delete_if{|k,v| k == task_name} )
     
    107
        end  
     
    108
     
    109
        def write_configuration(hash)
     
    110
          File.open(config_file, 'w') do |f| 
     
    111
            YAML.dump(hash, f)
     
    112
            f.close
     
    113
          end            
     
    114
        end  
     
    115
      
     
    116
    end
    23
    end
    117
     
    118
    RAILS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
     
    119
    RetroTasks.run
     
  • Updated spec/controllers/admin/tasks_controller_spec.rb (Quick Diff)

    spec/controllers/admin/tasks_controller_spec.rb

    66c1706af8813e
    5
    5
    6
      before do
    6
      before do
    7
        permit_access!
    7
        permit_access!
    8
        @tasks = [mock('Task1')]
    8
        @task = mock('Task1')
    9
        Retrospectiva::Tasks.stub!(:tasks).and_return(@tasks)
    9
        @tasks = [@task]
     
    10
        @parser = mock(Retrospectiva::TaskManager::Parser, :tasks => @tasks)
     
    11
        Retrospectiva::TaskManager::Parser.stub!(:new).and_return(@parser)
    10
      end
    12
      end
    11
    13
    12
      describe "handling GET /admin/tasks" do
    14
      describe "handling GET /admin/tasks" do
    ...
     
    ...
     
    17
        it_should_successfully_render_template('index')
    19
        it_should_successfully_render_template('index')
    18
    20
    19
        it "should query the tasks" do
    21
        it "should query the tasks" do
    20
          Retrospectiva::Tasks.should_receive(:tasks).and_return(@tasks)
    22
          Retrospectiva::TaskManager::Parser.should_receive(:new).and_return(@parser)
     
    23
          @parser.should_receive(:tasks).and_return(@tasks)
    21
          do_get
    24
          do_get
    22
        end
    25
        end
    23
    26
    ...
     
    ...
     
    32
      describe "handling PUT /admin/tasks/save" do
    35
      describe "handling PUT /admin/tasks/save" do
    33
    36
    34
        before do
    37
        before do
    35
          Retrospectiva::Tasks.stub!(:update).and_return true
    38
          Retrospectiva::TaskManager::Task.stub!(:update_or_create).and_return @task
    36
        end
    39
        end
    37
    40
    38
        def do_put
    41
        def do_put
    ...
     
    ...
     
    43
          get :save
    46
          get :save
    44
          response.code.should == '400'
    47
          response.code.should == '400'
    45
        end
    48
        end
    46
              
    49
    47
        it "should update the configuration" do
    50
        it "should find or create the affected task" do
    48
          Retrospectiva::Tasks.should_receive(:update).with('task_a' => 600).and_return true
    51
          Retrospectiva::TaskManager::Task.should_receive(:create_or_update).with('task_a', 600).and_return @task
    49
          do_put
    52
          do_put
    50
        end
    53
        end
    51
    54
              
    52
        it "should redirect to task overview" do
    55
        it "should redirect to task overview" do
    53
          do_put
    56
          do_put
    54
          response.should be_redirect
    57
          response.should be_redirect