tasks_scheduler 0.2.3 → 0.5.0
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.
- checksums.yaml +4 -4
- data/Rakefile +3 -1
- data/app/assets/stylesheets/tasks_scheduler.scss +4 -0
- data/app/controllers/scheduled_tasks_controller.rb +5 -4
- data/app/controllers/tasks_scheduler_daemon_controller.rb +8 -23
- data/app/controllers/tasks_scheduler_daemon_controller/_download_log.rb +42 -0
- data/app/helpers/scheduled_tasks_helper.rb +2 -0
- data/app/models/scheduled_task.rb +30 -15
- data/app/models/scheduled_task/checker.rb +20 -6
- data/app/models/scheduled_task/log.rb +8 -2
- data/app/models/scheduled_task/runner.rb +9 -5
- data/app/models/scheduled_task/status.rb +8 -4
- data/app/views/scheduled_tasks/status_content.html.erb +1 -0
- data/app/views/tasks_scheduler_daemon/_daemon.html.erb +11 -0
- data/app/views/tasks_scheduler_daemon/_logs.html.erb +12 -0
- data/app/views/tasks_scheduler_daemon/_results.html.erb +9 -0
- data/app/views/tasks_scheduler_daemon/_running_status.html.erb +0 -1
- data/app/views/tasks_scheduler_daemon/index.html.erb +3 -20
- data/config/initializers/assets.rb +3 -1
- data/config/routes.rb +4 -2
- data/db/migrate/20161122123828_create_scheduled_tasks.rb +5 -1
- data/db/migrate/20161123130153_add_status_attributes_to_scheduled_tasks.rb +5 -1
- data/db/migrate/20161124200712_add_pid_to_scheduled_tasks.rb +5 -1
- data/db/migrate/20161128163702_add_args_to_scheduled_tasks.rb +5 -1
- data/db/migrate/20180223155025_add_last_fail_status_to_scheduled_tasks.rb +5 -1
- data/db/migrate/20180302170138_add_enabled_to_scheduled_tasks.rb +5 -1
- data/exe/tasks_scheduler +3 -1
- data/exe/tasks_scheduler_run_task +3 -1
- data/lib/tasks_scheduler.rb +4 -8
- data/lib/tasks_scheduler/app_gem.rb +18 -0
- data/lib/tasks_scheduler/checker.rb +23 -4
- data/lib/tasks_scheduler/checker/log.rb +34 -0
- data/lib/tasks_scheduler/cron_parser_patch.rb +5 -1
- data/lib/tasks_scheduler/cron_scheduling_validator.rb +3 -0
- data/lib/tasks_scheduler/daemon.rb +20 -13
- data/lib/tasks_scheduler/engine.rb +5 -0
- data/lib/tasks_scheduler/version.rb +3 -1
- data/test/dummy/Rakefile +3 -1
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/bin/bundle +3 -1
- data/test/dummy/bin/rails +3 -1
- data/test/dummy/bin/rake +2 -0
- data/test/dummy/bin/setup +3 -1
- data/test/dummy/config.ru +2 -0
- data/test/dummy/config/application.rb +3 -1
- data/test/dummy/config/boot.rb +4 -2
- data/test/dummy/config/environment.rb +3 -1
- data/test/dummy/config/environments/development.rb +2 -0
- data/test/dummy/config/environments/production.rb +2 -0
- data/test/dummy/config/environments/test.rb +2 -0
- data/test/dummy/config/initializers/assets.rb +2 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +2 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +2 -0
- data/test/dummy/config/initializers/inflections.rb +1 -0
- data/test/dummy/config/initializers/mime_types.rb +1 -0
- data/test/dummy/config/initializers/session_store.rb +2 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/fixtures/scheduled_tasks.yml +2 -0
- data/test/models/scheduled_task_test.rb +6 -4
- data/test/test_helper.rb +6 -4
- metadata +91 -32
@@ -0,0 +1,12 @@
|
|
1
|
+
<h3>Logs</h3>
|
2
|
+
<ul>
|
3
|
+
<% ::TasksScheduler::Checker.instance.logs.each do |log| %>
|
4
|
+
<li>
|
5
|
+
<% if log.exist? %>
|
6
|
+
<%= link_to log.key, download_log_tasks_scheduler_daemon_path(log.key) %>
|
7
|
+
<% else %>
|
8
|
+
<span style="color: grey" title='Log "<%= log.key %>" does not exist.'><%= log.key %></span>
|
9
|
+
<% end %>
|
10
|
+
</li>
|
11
|
+
<% end %>
|
12
|
+
</ul>
|
@@ -1,22 +1,5 @@
|
|
1
1
|
<%= render partial: '/tasks_scheduler/navbar' %>
|
2
2
|
<h2><%= I18n.t(:tasks_scheduler_daemon) %></h2>
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
<strong>Actions: </strong>
|
7
|
-
<%= safe_join(::TasksScheduler::Daemon::ACTIONS.map do |action|
|
8
|
-
link_to action, execute_tasks_scheduler_daemon_path(action), method: :post
|
9
|
-
end, ' | ') %>
|
10
|
-
<br/>
|
11
|
-
<strong>Log: </strong>
|
12
|
-
<%= link_to 'download', download_log_tasks_scheduler_daemon_path %>
|
13
|
-
</p>
|
14
|
-
<% if @result %>
|
15
|
-
<h3>Results</h3>
|
16
|
-
<dl>
|
17
|
-
<% @result.each do |k, v| %>
|
18
|
-
<dt><%= k %></dt>
|
19
|
-
<dd><%= v.present? ? v : '-' %></dd>
|
20
|
-
<% end %>
|
21
|
-
</dl>
|
22
|
-
<% end %>
|
3
|
+
<%= render partial: 'daemon', locals: {status_label: 'Status:'} %>
|
4
|
+
<%= render partial: 'logs' %>
|
5
|
+
<%= render partial: 'results' %>
|
data/config/routes.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Rails.application.routes.draw do
|
2
4
|
resources(:scheduled_tasks) do
|
3
5
|
as_routes
|
@@ -15,6 +17,6 @@ Rails.application.routes.draw do
|
|
15
17
|
to: 'tasks_scheduler_daemon#execute', as: :execute_tasks_scheduler_daemon
|
16
18
|
get '/tasks_scheduler_daemon/status', to: 'tasks_scheduler_daemon#status',
|
17
19
|
as: :status_tasks_scheduler_daemon
|
18
|
-
get '/tasks_scheduler_daemon/download_log', to: 'tasks_scheduler_daemon#download_log',
|
19
|
-
|
20
|
+
get '/tasks_scheduler_daemon/download_log/:log_key', to: 'tasks_scheduler_daemon#download_log',
|
21
|
+
as: :download_log_tasks_scheduler_daemon
|
20
22
|
end
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateScheduledTasks < (
|
4
|
+
Rails.version < '5.2' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
|
5
|
+
)
|
2
6
|
def change
|
3
7
|
create_table :scheduled_tasks do |t|
|
4
8
|
t.string :scheduling
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddStatusAttributesToScheduledTasks < (
|
4
|
+
Rails.version < '5.2' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
|
5
|
+
)
|
2
6
|
def change
|
3
7
|
add_column :scheduled_tasks, :last_run_start, :datetime
|
4
8
|
add_column :scheduled_tasks, :last_run_successful_start, :datetime
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddPidToScheduledTasks < (
|
4
|
+
Rails.version < '5.2' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
|
5
|
+
)
|
2
6
|
def change
|
3
7
|
add_column :scheduled_tasks, :pid, :integer
|
4
8
|
end
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddArgsToScheduledTasks < (
|
4
|
+
Rails.version < '5.2' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
|
5
|
+
)
|
2
6
|
def change
|
3
7
|
add_column :scheduled_tasks, :args, :string
|
4
8
|
end
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddLastFailStatusToScheduledTasks < (
|
4
|
+
Rails.version < '5.2' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
|
5
|
+
)
|
2
6
|
def change
|
3
7
|
add_column :scheduled_tasks, :last_fail_status, :string
|
4
8
|
end
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddEnabledToScheduledTasks < (
|
4
|
+
Rails.version < '5.2' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
|
5
|
+
)
|
2
6
|
def change
|
3
7
|
add_column :scheduled_tasks, :enabled, :boolean, null: false, default: true
|
4
8
|
end
|
data/exe/tasks_scheduler
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'rubygems'
|
4
5
|
require 'daemons'
|
5
6
|
require 'fileutils'
|
6
7
|
|
7
8
|
def find_rails_root(dir = Dir.pwd)
|
8
|
-
|
9
|
+
raise 'Rails root not found' if ['', '/', '.'].include?(dir)
|
9
10
|
return dir if File.exist?(File.expand_path('config/environment.rb', dir))
|
11
|
+
|
10
12
|
rails_root(File.dirname(dir))
|
11
13
|
end
|
12
14
|
|
@@ -1,11 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'rubygems'
|
4
5
|
require 'daemons'
|
5
6
|
|
6
7
|
def find_rails_root(dir = Dir.pwd)
|
7
|
-
|
8
|
+
raise 'Rails root not found' if ['', '/', '.'].include?(dir)
|
8
9
|
return dir if File.exist?(File.expand_path('config/environment.rb', dir))
|
10
|
+
|
9
11
|
rails_root(File.dirname(dir))
|
10
12
|
end
|
11
13
|
|
data/lib/tasks_scheduler.rb
CHANGED
@@ -1,11 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
require 'parse-cron'
|
5
|
-
require 'tasks_scheduler/cron_scheduling_validator'
|
6
|
-
require 'tasks_scheduler/cron_parser_patch'
|
7
|
-
require 'tasks_scheduler/checker'
|
8
|
-
require 'tasks_scheduler/daemon'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_utils/require_sub'
|
9
4
|
|
10
5
|
module TasksScheduler
|
6
|
+
::EacRubyUtils.require_sub __FILE__
|
11
7
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_ruby_gems_utils/gem'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
module TasksScheduler
|
7
|
+
class AppGem < ::SimpleDelegator
|
8
|
+
include ::Singleton
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super(::EacRubyGemsUtils::Gem.new(::Rails.root))
|
12
|
+
end
|
13
|
+
|
14
|
+
def bundle(*args)
|
15
|
+
super(*args).chdir_root.envvar('RAILS_ENV', ::Rails.env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,9 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tasks_scheduler/checker/log'
|
4
|
+
|
1
5
|
module TasksScheduler
|
2
6
|
class Checker
|
3
7
|
include Singleton
|
4
8
|
|
5
9
|
CHECK_INTERVAL = 15
|
6
|
-
LOG_ON_FILE_ENV_KEY = 'TASKS_SCHEDULER_LOG_ON_FILE'
|
10
|
+
LOG_ON_FILE_ENV_KEY = 'TASKS_SCHEDULER_LOG_ON_FILE'
|
11
|
+
LOGS_KEYS = %w[rails stdout stderr].freeze
|
7
12
|
|
8
13
|
def run
|
9
14
|
check_log
|
@@ -18,15 +23,29 @@ module TasksScheduler
|
|
18
23
|
end
|
19
24
|
|
20
25
|
def log_path
|
21
|
-
|
26
|
+
rais_log.path
|
27
|
+
end
|
28
|
+
|
29
|
+
def logs
|
30
|
+
LOGS_KEYS.map { |key| send("#{key}_log") }
|
31
|
+
end
|
32
|
+
|
33
|
+
LOGS_KEYS.each do |log_key|
|
34
|
+
class_eval <<CODE, __FILE__, __LINE__ + 1
|
35
|
+
def #{log_key}_log
|
36
|
+
@#{log_key}_log ||= ::TasksScheduler::Checker::Log.new('#{log_key}')
|
37
|
+
end
|
38
|
+
CODE
|
22
39
|
end
|
23
40
|
|
24
41
|
private
|
25
42
|
|
26
43
|
def check_log
|
27
44
|
return unless log_on_file?
|
28
|
-
|
29
|
-
::Rails.logger = ::Logger.new(
|
45
|
+
|
46
|
+
::Rails.logger = ::Logger.new(rails_log.path)
|
47
|
+
$stdout.reopen(stdout_log.path, 'w')
|
48
|
+
$stderr.reopen(stderr_log.path, 'w')
|
30
49
|
end
|
31
50
|
|
32
51
|
def log_on_file?
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module TasksScheduler
|
6
|
+
class Checker
|
7
|
+
class Log
|
8
|
+
class << self
|
9
|
+
def logs_directory
|
10
|
+
@logs_directory ||= ::Rails.root.join('log', 'tasks_scheduler', 'checker')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :key
|
15
|
+
|
16
|
+
def initialize(key)
|
17
|
+
@key = key
|
18
|
+
::FileUtils.mkdir_p(dirname)
|
19
|
+
end
|
20
|
+
|
21
|
+
def dirname
|
22
|
+
::File.dirname(path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def exist?
|
26
|
+
::File.exist?(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def path
|
30
|
+
self.class.logs_directory.join("#{key}.log")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'parse-cron'
|
4
|
+
|
1
5
|
module TasksScheduler
|
2
6
|
module CronParserPatch
|
3
7
|
class TasksSchedulerTimeSource
|
4
8
|
class << self
|
5
|
-
def local(year, month, day, hour, min, second)
|
9
|
+
def local(year, month, day, hour, min, second) # rubocop:disable Metrics/ParameterLists
|
6
10
|
Time.utc(year, month, day, hour, min, second)
|
7
11
|
end
|
8
12
|
|
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TasksScheduler
|
2
4
|
class CronSchedulingValidator < ActiveModel::EachValidator
|
3
5
|
def validate_each(record, attribute, value)
|
4
6
|
return if value_valid?(value)
|
7
|
+
|
5
8
|
record.errors[attribute] << (options[:message] ||
|
6
9
|
I18n.translate(:cron_scheduling_validator_error_message))
|
7
10
|
end
|
@@ -1,28 +1,35 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tasks_scheduler/app_gem'
|
2
4
|
|
3
5
|
module TasksScheduler
|
4
6
|
class Daemon
|
5
|
-
ACTIONS = %w
|
7
|
+
ACTIONS = %w[status start stop restart].freeze
|
6
8
|
|
7
9
|
class << self
|
8
|
-
def
|
10
|
+
def daemon_command(action)
|
9
11
|
raise "Action not allowed: #{action} (Allowed: #{ACTIONS})" unless ACTIONS.include?(action)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
|
13
|
+
::TasksScheduler::AppGem.instance.bundle('exec', 'tasks_scheduler', action)
|
14
|
+
.envvar(::TasksScheduler::Checker::LOG_ON_FILE_ENV_KEY, '1')
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(action)
|
18
|
+
command = daemon_command(action)
|
19
|
+
result = command.execute
|
20
|
+
{
|
21
|
+
action: action, env_args: env_args_to_s(command), command: command.to_s,
|
22
|
+
status: result.fetch(:exit_code), stdout: result.fetch(:stdout),
|
23
|
+
stderr: result.fetch(:stderr)
|
24
|
+
}
|
18
25
|
end
|
19
26
|
|
20
27
|
def running?
|
21
28
|
execute('status')[:status].zero?
|
22
29
|
end
|
23
30
|
|
24
|
-
def
|
25
|
-
{
|
31
|
+
def env_args_to_s(command)
|
32
|
+
command.send(:extra_options).fetch(:envvars).map { |k, v| "#{k}=#{v}" }.join(' | ')
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
data/test/dummy/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
4
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
5
|
|
4
|
-
require File.expand_path('
|
6
|
+
require File.expand_path('config/application', __dir__)
|
5
7
|
|
6
8
|
Rails.application.load_tasks
|
data/test/dummy/bin/bundle
CHANGED
data/test/dummy/bin/rails
CHANGED
data/test/dummy/bin/rake
CHANGED
data/test/dummy/bin/setup
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'pathname'
|
3
5
|
|
4
6
|
# path to your application root.
|
5
|
-
APP_ROOT = Pathname.new File.expand_path('
|
7
|
+
APP_ROOT = Pathname.new File.expand_path('..', __dir__)
|
6
8
|
|
7
9
|
Dir.chdir APP_ROOT do
|
8
10
|
# This script is a starting point to setup your application.
|