tasks_scheduler 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +33 -0
- data/app/assets/javascripts/tasks_scheduler.js +59 -0
- data/app/assets/stylesheets/tasks_scheduler.scss +34 -0
- data/app/controllers/scheduled_tasks_controller.rb +45 -0
- data/app/helpers/scheduled_tasks_helper.rb +17 -0
- data/app/models/scheduled_task.rb +61 -0
- data/app/models/scheduled_task/checker.rb +54 -0
- data/app/models/scheduled_task/log.rb +28 -0
- data/app/models/scheduled_task/runner.rb +50 -0
- data/app/models/scheduled_task/status.rb +53 -0
- data/app/views/scheduled_tasks/log.html.erb +9 -0
- data/app/views/scheduled_tasks/status.html.erb +7 -0
- data/app/views/scheduled_tasks/status_content.html.erb +47 -0
- data/config/initializers/assets.rb +1 -0
- data/config/locales/en.yml +22 -0
- data/config/locales/pt-BR.yml +22 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20161122123828_create_scheduled_tasks.rb +11 -0
- data/db/migrate/20161123130153_add_status_attributes_to_scheduled_tasks.rb +9 -0
- data/db/migrate/20161124200712_add_pid_to_scheduled_tasks.rb +5 -0
- data/db/migrate/20161128163702_add_args_to_scheduled_tasks.rb +5 -0
- data/exe/tasks_scheduler +19 -0
- data/exe/tasks_scheduler_run_task +14 -0
- data/lib/tasks_scheduler.rb +9 -0
- data/lib/tasks_scheduler/checker.rb +20 -0
- data/lib/tasks_scheduler/cron_parser_patch.rb +27 -0
- data/lib/tasks_scheduler/cron_scheduling_validator.rb +18 -0
- data/lib/tasks_scheduler/engine.rb +9 -0
- data/lib/tasks_scheduler/version.rb +3 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +81 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +9 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/schema.rb +31 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/fixtures/scheduled_tasks.yml +4 -0
- data/test/models/scheduled_task_test.rb +72 -0
- data/test/test_helper.rb +36 -0
- metadata +223 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f9254c9d8a1935a5a50a998c497502693a00a062
|
4
|
+
data.tar.gz: f1161054c8feebbad1210375262e0ad6e925f56b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dd68161f972bc3632c370b1cd6ebdb18c4e825719156022324f3327fb743f4d9ce7e5de6bf3ffe991aa1143ffa46eb1c9dd696fd9f2561ccf991af7935138c8c
|
7
|
+
data.tar.gz: b05bd8fbcaab8d142be5798d0d47b5701368237d492eb5b4f108c6b3ffd9e0b8a726c9d40930b8210596890a53c46fd07f61ad5b014caee8ddd8e321ab155461
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Eduardo H. Bogoni
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'TasksScheduler'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
task default: :test
|
@@ -0,0 +1,59 @@
|
|
1
|
+
//= require active_scaffold
|
2
|
+
|
3
|
+
function TasksScheduler() {
|
4
|
+
}
|
5
|
+
|
6
|
+
TasksScheduler.Status = function () {
|
7
|
+
}
|
8
|
+
|
9
|
+
// Shortcut
|
10
|
+
var _S = TasksScheduler.Status;
|
11
|
+
|
12
|
+
_S.initialized = false;
|
13
|
+
|
14
|
+
_S.init = function (url, interval_max) {
|
15
|
+
if (!_S.initialized) {
|
16
|
+
_S.initialized = true;
|
17
|
+
_S.url = url;
|
18
|
+
_S.interval_max = interval_max;
|
19
|
+
_S.update();
|
20
|
+
}
|
21
|
+
};
|
22
|
+
|
23
|
+
_S.content = function () {
|
24
|
+
return $('#TaskScheduler_Status_Content');
|
25
|
+
};
|
26
|
+
|
27
|
+
_S.status = function () {
|
28
|
+
return $('#TaskScheduler_Status_Status');
|
29
|
+
};
|
30
|
+
|
31
|
+
_S.update_status = function () {
|
32
|
+
_S.status().html(
|
33
|
+
"Updating in " + _S.interval + " seconds..."
|
34
|
+
);
|
35
|
+
};
|
36
|
+
|
37
|
+
_S.check = function () {
|
38
|
+
if (_S.interval <= 0) {
|
39
|
+
_S.update();
|
40
|
+
} else {
|
41
|
+
_S.interval--;
|
42
|
+
_S.update_status();
|
43
|
+
setTimeout(_S.check, 1000);
|
44
|
+
}
|
45
|
+
};
|
46
|
+
|
47
|
+
_S.update = function () {
|
48
|
+
$.ajax({
|
49
|
+
url: _S.url,
|
50
|
+
success: function (result) {
|
51
|
+
_S.content().html(result);
|
52
|
+
},
|
53
|
+
complete: function (result) {
|
54
|
+
_S.interval = _S.interval_max + 1;
|
55
|
+
_S.last_update = new Date();
|
56
|
+
_S.check();
|
57
|
+
}
|
58
|
+
});
|
59
|
+
};
|
@@ -0,0 +1,34 @@
|
|
1
|
+
@import 'active_scaffold';
|
2
|
+
|
3
|
+
#TaskScheduler_Status_Status {
|
4
|
+
font-size: small;
|
5
|
+
margin-bottom: 1.0em;
|
6
|
+
}
|
7
|
+
|
8
|
+
#TaskScheduler_Status_Content {
|
9
|
+
table {
|
10
|
+
border-collapse: collapse;
|
11
|
+
|
12
|
+
td, th {
|
13
|
+
border: thin solid black;
|
14
|
+
padding: 0.3em;
|
15
|
+
text-align: center;
|
16
|
+
}
|
17
|
+
|
18
|
+
td.status_running {
|
19
|
+
color: blue;
|
20
|
+
}
|
21
|
+
|
22
|
+
td.status_waiting {
|
23
|
+
color: darkgrey;
|
24
|
+
}
|
25
|
+
|
26
|
+
td.status_failed {
|
27
|
+
color: red;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
.last_run {
|
32
|
+
font-weight: bold;
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class ScheduledTasksController < ApplicationController
|
2
|
+
active_scaffold :scheduled_task do |conf|
|
3
|
+
[:create, :update, :list].each do |action|
|
4
|
+
conf.send(action).columns.exclude(:next_run, :last_run_start,
|
5
|
+
:last_run_successful_start, :last_run_unsuccessful_start,
|
6
|
+
:last_run_successful_end, :last_run_unsuccessful_end,
|
7
|
+
:pid)
|
8
|
+
end
|
9
|
+
conf.columns[:task].form_ui = :select
|
10
|
+
conf.columns[:task].options ||= {}
|
11
|
+
conf.columns[:task].options[:options] = task_column_options
|
12
|
+
conf.action_links.add :status, label: I18n.t(:tasks_scheduler_status), position: true
|
13
|
+
conf.action_links.add :run_now, label: I18n.t(:run_now), type: :member,
|
14
|
+
crud_type: :update, method: :put, position: false
|
15
|
+
end
|
16
|
+
|
17
|
+
def log
|
18
|
+
record = find_if_allowed(params[:id], :read)
|
19
|
+
@log_file = record.log_file(params[:identifier])
|
20
|
+
end
|
21
|
+
|
22
|
+
def status
|
23
|
+
end
|
24
|
+
|
25
|
+
def status_content
|
26
|
+
@scheduled_tasks = ::ScheduledTask.order(task: :asc, scheduling: :asc)
|
27
|
+
render layout: false
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_now
|
31
|
+
process_action_link_action do |record|
|
32
|
+
record.update_attributes!(next_run: Time.zone.now)
|
33
|
+
record.reload
|
34
|
+
flash[:info] = "Next run adjusted to #{record.next_run}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
private
|
40
|
+
|
41
|
+
def task_column_options
|
42
|
+
::ScheduledTask.rake_tasks.map { |st| [st, st] }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ScheduledTasksHelper
|
2
|
+
def scheduled_tasks_status_time(time)
|
3
|
+
if time.present?
|
4
|
+
I18n.l(time, format: :short)
|
5
|
+
else
|
6
|
+
'-'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def scheduled_tasks_log(scheduled_task, log_identifier)
|
11
|
+
if File.exist?(scheduled_task.log_file(log_identifier))
|
12
|
+
link_to I18n.t(:log), log_scheduled_task_path(scheduled_task, identifier: log_identifier)
|
13
|
+
else
|
14
|
+
'-'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
class ScheduledTask < ActiveRecord::Base
|
4
|
+
include ::ScheduledTask::Checker
|
5
|
+
include ::ScheduledTask::Log
|
6
|
+
include ::ScheduledTask::Runner
|
7
|
+
include ::ScheduledTask::Status
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def rake_tasks
|
11
|
+
@rake_tasks ||= begin
|
12
|
+
Rails.application.load_tasks
|
13
|
+
Rake.application.tasks.map(&:name)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
validates :scheduling, presence: true, 'tasks_scheduler/cron_scheduling': true
|
19
|
+
validates :task, presence: true, inclusion: { in: rake_tasks }
|
20
|
+
|
21
|
+
STATUS_RUNNING = 'running'
|
22
|
+
STATUS_FAILED = 'failed'
|
23
|
+
STATUS_WAITING = 'waiting'
|
24
|
+
|
25
|
+
LOG_RUNNING = 'running'
|
26
|
+
LOG_SUCCESSFUL = 'successful'
|
27
|
+
LOG_UNSUCCESSFUL = 'unsuccessful'
|
28
|
+
|
29
|
+
def cron_parser
|
30
|
+
@cron_parser ||= ::CronParser.new(scheduling)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"S: #{scheduling}, T: #{task}, NR: #{next_run.present? ? next_run.in_time_zone : '-'}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def calculate_next_run(time = nil)
|
38
|
+
if time.present?
|
39
|
+
cron_parser.next(time.utc)
|
40
|
+
else
|
41
|
+
cron_parser.next
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_attribute(name, value)
|
46
|
+
@cron_parser = nil if name == 'scheduling'
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_running?
|
51
|
+
return false if pid.nil?
|
52
|
+
Process.kill(0, pid)
|
53
|
+
return true
|
54
|
+
rescue Errno::EPERM
|
55
|
+
raise "No permission to query #{pid}!"
|
56
|
+
rescue Errno::ESRCH
|
57
|
+
return false
|
58
|
+
rescue
|
59
|
+
raise "Unable to determine status for #{pid}"
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
class ScheduledTask < ActiveRecord::Base
|
4
|
+
module Checker
|
5
|
+
def check
|
6
|
+
check_banner
|
7
|
+
if process_running?
|
8
|
+
check_log("Already running (PID: #{pid})")
|
9
|
+
return
|
10
|
+
end
|
11
|
+
if next_run.present?
|
12
|
+
check_task_with_next_run
|
13
|
+
else
|
14
|
+
check_task_without_next_run
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def check_log(message, method = :info)
|
21
|
+
Rails.logger.send(method, "TASK_CHECK(#{id}): #{message}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_banner
|
25
|
+
check_log("Task: #{self}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_task_without_next_run
|
29
|
+
check_log('Next run blank')
|
30
|
+
update_attributes!(next_run: calculate_next_run)
|
31
|
+
check_log("Next run @scheduled_taskored: #{next_run.in_time_zone}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_task_with_next_run
|
35
|
+
if next_run < Time.zone.now
|
36
|
+
check_log('Next run reached. Running...')
|
37
|
+
spawn_task
|
38
|
+
else
|
39
|
+
check_log('Next run not reached')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def spawn_task
|
44
|
+
params = ['bundle', 'exec', 'tasks_scheduler_run_task', id.to_s]
|
45
|
+
check_log("Spawn command: #{params}")
|
46
|
+
spawn_pid = nil
|
47
|
+
Dir.chdir(Rails.root) do
|
48
|
+
spawn_pid = Process.spawn(*params)
|
49
|
+
end
|
50
|
+
Process.detach(spawn_pid)
|
51
|
+
update_attributes!(pid: spawn_pid)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class ScheduledTask < ActiveRecord::Base
|
2
|
+
module Log
|
3
|
+
def log_file(identifier)
|
4
|
+
unless log_identifiers.include?(identifier)
|
5
|
+
fail "Log identifier unknown: \"#{identifier}\" (Valid: #{log_identifiers})"
|
6
|
+
end
|
7
|
+
Rails.root.join('log', 'tasks_scheduler', "#{id}_#{identifier}.log")
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def log_identifiers
|
13
|
+
[LOG_RUNNING, LOG_UNSUCCESSFUL, LOG_SUCCESSFUL]
|
14
|
+
end
|
15
|
+
|
16
|
+
def log_on_start
|
17
|
+
FileUtils.mkdir_p(File.dirname(log_file(LOG_RUNNING)))
|
18
|
+
File.unlink(log_file(LOG_RUNNING)) if File.exist?(log_file(LOG_RUNNING))
|
19
|
+
Rails.logger = ActiveSupport::Logger.new(log_file(LOG_RUNNING))
|
20
|
+
end
|
21
|
+
|
22
|
+
def log_on_end(exception)
|
23
|
+
target_log = exception ? log_file(LOG_UNSUCCESSFUL) : log_file(LOG_SUCCESSFUL)
|
24
|
+
File.unlink(target_log) if File.exist?(target_log)
|
25
|
+
File.rename(log_file(LOG_RUNNING), target_log)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class ScheduledTask < ActiveRecord::Base
|
2
|
+
module Runner
|
3
|
+
def run
|
4
|
+
log_on_start
|
5
|
+
run_banner
|
6
|
+
return if process_running? && pid != Process.pid
|
7
|
+
status_on_start
|
8
|
+
exception = invoke_task
|
9
|
+
run_log(exception, :fatal) if exception
|
10
|
+
status_on_end(exception)
|
11
|
+
log_on_end(exception)
|
12
|
+
run_log("Next run: #{next_run.in_time_zone}")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def run_log(message, method = :info)
|
18
|
+
if message.is_a?(Exception)
|
19
|
+
run_log("#{message.class}: #{message.message}")
|
20
|
+
run_log(message.backtrace.join("\n"))
|
21
|
+
else
|
22
|
+
Rails.logger.send(method, "TASK_RUN(#{id}): #{message}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_banner
|
27
|
+
run_log("Task: #{self}")
|
28
|
+
run_log("PID: #{pid ? pid : '-'} (Current: #{Process.pid})")
|
29
|
+
run_log("Process running? #{process_running? ? 'Yes' : 'No'}")
|
30
|
+
end
|
31
|
+
|
32
|
+
def invoke_task
|
33
|
+
exception = nil
|
34
|
+
begin
|
35
|
+
Rake::Task.clear
|
36
|
+
Rails.application.load_tasks
|
37
|
+
Rake::Task[task].invoke(invoke_args)
|
38
|
+
rescue StandardError => ex
|
39
|
+
run_log(ex, :fatal)
|
40
|
+
exception = ex
|
41
|
+
end
|
42
|
+
exception
|
43
|
+
end
|
44
|
+
|
45
|
+
def invoke_args
|
46
|
+
return [] unless args.present?
|
47
|
+
args.split('|')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class ScheduledTask < ActiveRecord::Base
|
2
|
+
module Status
|
3
|
+
def status
|
4
|
+
return STATUS_RUNNING if running?
|
5
|
+
return STATUS_WAITING if waiting?
|
6
|
+
return STATUS_FAILED if failed?
|
7
|
+
fail "Unknown status (#{status_attributes_values})"
|
8
|
+
end
|
9
|
+
|
10
|
+
def running?
|
11
|
+
last_run_start.present?
|
12
|
+
end
|
13
|
+
|
14
|
+
def waiting?
|
15
|
+
return true if ended?(last_run_successful_end, last_run_unsuccessful_end)
|
16
|
+
status_attributes.all? { |a| send(a).blank? }
|
17
|
+
end
|
18
|
+
|
19
|
+
def failed?
|
20
|
+
ended?(last_run_unsuccessful_end, last_run_successful_end)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ended?(time, oposite_time)
|
24
|
+
!running? && time.present? && (oposite_time.blank? || oposite_time < time)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def status_on_start
|
30
|
+
update_attributes!(last_run_start: Time.zone.now)
|
31
|
+
end
|
32
|
+
|
33
|
+
def status_on_end(exception)
|
34
|
+
update_attributes!(
|
35
|
+
next_run: calculate_next_run,
|
36
|
+
(exception ? :last_run_unsuccessful_start : :last_run_successful_start) => last_run_start,
|
37
|
+
(exception ? :last_run_unsuccessful_end : :last_run_successful_end) => Time.zone.now,
|
38
|
+
last_run_start: nil,
|
39
|
+
pid: nil
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def status_attributes
|
44
|
+
%w(start successful_start successful_end unsuccessful_start unsuccessful_end).map do |a|
|
45
|
+
"last_run_#{a}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def status_attributes_values
|
50
|
+
status_attributes.map { |a| "#{a}: #{send(a)}" }.join(', ')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|