inst-jobs 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/inst_job +4 -0
- data/db/migrate/20101216224513_create_delayed_jobs.rb +40 -0
- data/db/migrate/20110208031356_add_delayed_jobs_tag.rb +14 -0
- data/db/migrate/20110426161613_add_delayed_jobs_max_attempts.rb +13 -0
- data/db/migrate/20110516225834_add_delayed_jobs_strand.rb +14 -0
- data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +26 -0
- data/db/migrate/20110610213249_optimize_delayed_jobs.rb +40 -0
- data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +52 -0
- data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +31 -0
- data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +15 -0
- data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +80 -0
- data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +15 -0
- data/db/migrate/20120608191051_add_jobs_run_at_index.rb +15 -0
- data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +13 -0
- data/db/migrate/20140505215131_add_failed_jobs_original_job_id.rb +13 -0
- data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +13 -0
- data/db/migrate/20140505223637_drop_failed_jobs_original_id.rb +13 -0
- data/db/migrate/20140512213941_add_source_to_jobs.rb +15 -0
- data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +70 -0
- data/db/migrate/20151123210429_add_expires_at_to_jobs.rb +15 -0
- data/db/migrate/20151210162949_improve_max_concurrent.rb +50 -0
- data/lib/delayed/backend/active_record.rb +340 -0
- data/lib/delayed/backend/base.rb +335 -0
- data/lib/delayed/backend/redis/bulk_update.lua +50 -0
- data/lib/delayed/backend/redis/destroy_job.lua +2 -0
- data/lib/delayed/backend/redis/enqueue.lua +29 -0
- data/lib/delayed/backend/redis/fail_job.lua +5 -0
- data/lib/delayed/backend/redis/find_available.lua +3 -0
- data/lib/delayed/backend/redis/functions.rb +57 -0
- data/lib/delayed/backend/redis/get_and_lock_next_available.lua +17 -0
- data/lib/delayed/backend/redis/includes/jobs_common.lua +203 -0
- data/lib/delayed/backend/redis/job.rb +497 -0
- data/lib/delayed/backend/redis/set_running.lua +5 -0
- data/lib/delayed/backend/redis/tickle_strand.lua +2 -0
- data/lib/delayed/batch.rb +56 -0
- data/lib/delayed/cli.rb +101 -0
- data/lib/delayed/daemon.rb +103 -0
- data/lib/delayed/engine.rb +4 -0
- data/lib/delayed/job_tracking.rb +31 -0
- data/lib/delayed/lifecycle.rb +90 -0
- data/lib/delayed/log_tailer.rb +22 -0
- data/lib/delayed/message_sending.rb +134 -0
- data/lib/delayed/performable_method.rb +52 -0
- data/lib/delayed/periodic.rb +85 -0
- data/lib/delayed/plugin.rb +22 -0
- data/lib/delayed/pool.rb +161 -0
- data/lib/delayed/server/helpers.rb +28 -0
- data/lib/delayed/server/public/css/app.css +12 -0
- data/lib/delayed/server/public/js/app.js +132 -0
- data/lib/delayed/server/views/index.erb +90 -0
- data/lib/delayed/server/views/layout.erb +47 -0
- data/lib/delayed/server.rb +120 -0
- data/lib/delayed/settings.rb +90 -0
- data/lib/delayed/testing.rb +32 -0
- data/lib/delayed/version.rb +3 -0
- data/lib/delayed/work_queue/in_process.rb +13 -0
- data/lib/delayed/work_queue/parent_process.rb +180 -0
- data/lib/delayed/worker.rb +234 -0
- data/lib/delayed/yaml_extensions.rb +109 -0
- data/lib/delayed_job.rb +46 -0
- data/lib/inst-jobs.rb +1 -0
- data/spec/active_record_job_spec.rb +246 -0
- data/spec/delayed/cli_spec.rb +23 -0
- data/spec/delayed/daemon_spec.rb +35 -0
- data/spec/delayed/server_spec.rb +63 -0
- data/spec/delayed/settings_spec.rb +32 -0
- data/spec/delayed/work_queue/in_process_spec.rb +31 -0
- data/spec/delayed/work_queue/parent_process_spec.rb +159 -0
- data/spec/delayed/worker_spec.rb +16 -0
- data/spec/gemfiles/32.gemfile +6 -0
- data/spec/gemfiles/40.gemfile +5 -0
- data/spec/gemfiles/41.gemfile +5 -0
- data/spec/gemfiles/42.gemfile +5 -0
- data/spec/migrate/20140924140513_add_story_table.rb +7 -0
- data/spec/redis_job_spec.rb +140 -0
- data/spec/sample_jobs.rb +28 -0
- data/spec/shared/delayed_batch.rb +85 -0
- data/spec/shared/delayed_method.rb +419 -0
- data/spec/shared/performable_method.rb +66 -0
- data/spec/shared/shared_backend.rb +819 -0
- data/spec/shared/testing.rb +48 -0
- data/spec/shared/worker.rb +378 -0
- data/spec/shared_jobs_specs.rb +15 -0
- data/spec/spec_helper.rb +97 -0
- metadata +390 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module Delayed
|
2
|
+
class Server
|
3
|
+
module Helpers
|
4
|
+
def h(text)
|
5
|
+
Rack::Utils.escape_html(text)
|
6
|
+
end
|
7
|
+
|
8
|
+
def url_path(*path_parts)
|
9
|
+
[path_prefix, path_parts].join('/').squeeze('/')
|
10
|
+
end
|
11
|
+
|
12
|
+
def path_prefix
|
13
|
+
request.env['SCRIPT_NAME']
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_javascript_env
|
17
|
+
{
|
18
|
+
Routes: {
|
19
|
+
root: path_prefix,
|
20
|
+
running: url_path('running'),
|
21
|
+
tags: url_path('tags'),
|
22
|
+
jobs: url_path('jobs'),
|
23
|
+
}
|
24
|
+
}.to_json
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
(function () {
|
2
|
+
var Delayed = {};
|
3
|
+
|
4
|
+
Delayed.Render = {};
|
5
|
+
Delayed.Render.attempts = function (previousAttempts, callType, jobData) {
|
6
|
+
var thisAttempt = parseInt(previousAttempts, 10) + 1;
|
7
|
+
switch(callType) {
|
8
|
+
case "display":
|
9
|
+
return thisAttempt + "/" + jobData.max_attempts;
|
10
|
+
default:
|
11
|
+
return thisAttempt;
|
12
|
+
}
|
13
|
+
};
|
14
|
+
|
15
|
+
Delayed.Render.runTime = function (lockedAt, callType) {
|
16
|
+
var elapsed, days, hours, minutes, seconds, remaining, formattedTime;
|
17
|
+
elapsed = Math.round((new Date().getTime() - Date.parse(lockedAt)) / 1000);
|
18
|
+
switch(callType) {
|
19
|
+
case "display": {
|
20
|
+
days = Math.floor(elapsed / 86400);
|
21
|
+
remaining = elapsed - (days * 86400);
|
22
|
+
hours = Math.floor(remaining / 3600);
|
23
|
+
remaining = remaining - (hours * 3600);
|
24
|
+
minutes = Math.floor(remaining / 60);
|
25
|
+
seconds = remaining - (minutes * 60);
|
26
|
+
formattedTime = ""
|
27
|
+
if(days > 0) {
|
28
|
+
formattedTime = days + "d "
|
29
|
+
}
|
30
|
+
formattedTime = formattedTime + ("0" + hours).slice(-2) + ":" + ("0" + minutes).slice(-2) + ":" + ("0" + seconds).slice(-2);
|
31
|
+
return formattedTime;
|
32
|
+
}
|
33
|
+
default:
|
34
|
+
return elapsed;
|
35
|
+
}
|
36
|
+
};
|
37
|
+
|
38
|
+
$(document).ready(function () {
|
39
|
+
var runningTable, runningInterval, tagsTable, tagsInterval, jobsTable, jobsInterval
|
40
|
+
runningTable = $('#running').DataTable({
|
41
|
+
"autoWidth": false,
|
42
|
+
"bSort": false,
|
43
|
+
"paging": false,
|
44
|
+
"processing": true,
|
45
|
+
"searching": false,
|
46
|
+
"scrollY": "200px",
|
47
|
+
"serverSide": true,
|
48
|
+
"order": [[5, "desc"]],
|
49
|
+
"ajax": ENV.Routes.running,
|
50
|
+
"columns": [
|
51
|
+
{"data": "id"},
|
52
|
+
{"data": "locked_by", "className": "worker"},
|
53
|
+
{"data": "tag", "className": "tag"},
|
54
|
+
{"data": "attempts", "render": Delayed.Render.attempts, "className": "attempts"},
|
55
|
+
{"data": "strand", "className": "strand"},
|
56
|
+
{"data": "locked_at", "render": Delayed.Render.runTime}
|
57
|
+
]
|
58
|
+
});
|
59
|
+
runningInterval = setInterval(function () { runningTable.ajax.reload(); }, 2000);
|
60
|
+
|
61
|
+
tagsTable = $("#tags").DataTable({
|
62
|
+
"autoWidth": false,
|
63
|
+
"bSort": false,
|
64
|
+
"paging": false,
|
65
|
+
"processing": true,
|
66
|
+
"searching": false,
|
67
|
+
"scrollY": "200px",
|
68
|
+
"order": [[1, "desc"]],
|
69
|
+
"ajax": ENV.Routes.tags,
|
70
|
+
"columns": [
|
71
|
+
{"data": "tag", "className": "tag"},
|
72
|
+
{"data": "count"}
|
73
|
+
]
|
74
|
+
});
|
75
|
+
tagsInterval = setInterval(function () { tagsTable.ajax.reload(); }, 10000);
|
76
|
+
|
77
|
+
jobsTable = $("#jobs").DataTable({
|
78
|
+
"autoWidth": false,
|
79
|
+
"bSort": false,
|
80
|
+
"paging": true,
|
81
|
+
"processing": true,
|
82
|
+
"searching": false,
|
83
|
+
"scrollY": "200px",
|
84
|
+
"serverSide": true,
|
85
|
+
"order": [[1, "desc"]],
|
86
|
+
"ajax": {
|
87
|
+
"url": ENV.Routes.jobs,
|
88
|
+
"data": function (data) {
|
89
|
+
data.flavor = $("select#current_jobs_flavor").val();
|
90
|
+
data.search_term = $("input#jobs_search_term").val();
|
91
|
+
}
|
92
|
+
},
|
93
|
+
"columns": [
|
94
|
+
{"data": "id"},
|
95
|
+
{"data": "tag", "className": "tag"},
|
96
|
+
{"data": "attempts", "render": Delayed.Render.attempts},
|
97
|
+
{"data": "priority"},
|
98
|
+
{"data": "strand"},
|
99
|
+
{"data": "run_at"}
|
100
|
+
]
|
101
|
+
});
|
102
|
+
|
103
|
+
$('body').on('click', '.refresh_jobs_link', function(event) {
|
104
|
+
event.preventDefault();
|
105
|
+
jobsTable.ajax.reload();
|
106
|
+
return true
|
107
|
+
});
|
108
|
+
|
109
|
+
$('body').on('change', 'select#current_jobs_flavor', function (event) {
|
110
|
+
event.preventDefault();
|
111
|
+
$selectBox = $(this);
|
112
|
+
$selectedOption = $($selectBox.children(':selected'));
|
113
|
+
$searchDiv = $('div#job_search');
|
114
|
+
|
115
|
+
if ($selectedOption.data('requires-search')) {
|
116
|
+
$searchDiv.show();
|
117
|
+
} else {
|
118
|
+
$searchDiv.hide();
|
119
|
+
}
|
120
|
+
|
121
|
+
jobsTable.ajax.reload();
|
122
|
+
return true
|
123
|
+
});
|
124
|
+
|
125
|
+
$('body').on('keyup', '#jobs_search_term', function (event) {
|
126
|
+
if (event.keyCode == 13) {
|
127
|
+
jobsTable.ajax.reload();
|
128
|
+
}
|
129
|
+
return true
|
130
|
+
});
|
131
|
+
});
|
132
|
+
})();
|
@@ -0,0 +1,90 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div class="col-md-8">
|
3
|
+
<h2>Running</h2>
|
4
|
+
<table id="running" class="table table-striped table-bordered">
|
5
|
+
<thead>
|
6
|
+
<tr>
|
7
|
+
<th>ID</th>
|
8
|
+
<th>Worker</th>
|
9
|
+
<th>Tag</th>
|
10
|
+
<th>Attempt</th>
|
11
|
+
<th>Strand</th>
|
12
|
+
<th>Runtime</th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody>
|
16
|
+
</tbody>
|
17
|
+
</table>
|
18
|
+
</div>
|
19
|
+
<div class="col-md-4">
|
20
|
+
<h2>Tags</h2>
|
21
|
+
<table id="tags" class="table table-striped table-bordered">
|
22
|
+
<thead>
|
23
|
+
<tr>
|
24
|
+
<th>Tag</th>
|
25
|
+
<th>Count</th>
|
26
|
+
</tr>
|
27
|
+
</thead>
|
28
|
+
<tbody>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="row">
|
35
|
+
<div class="col-md-12">
|
36
|
+
<h2>Jobs List</h2>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class="row">
|
41
|
+
<div class="form-group">
|
42
|
+
<div class="col-md-2">
|
43
|
+
<select id="current_jobs_flavor" class="form-control">
|
44
|
+
<option value="current">Current</option>
|
45
|
+
<option value="future">Future</option>
|
46
|
+
<option value="failed">Failed</option>
|
47
|
+
<option value="id" data-requires-search="true">ID</option>
|
48
|
+
<option value="strand" data-requires-search="true">Strand</option>
|
49
|
+
<option value="tag" data-requires-search="true">Tag</option>
|
50
|
+
</select>
|
51
|
+
</div>
|
52
|
+
<div class="col-md-3">
|
53
|
+
<!-- this inline style makes me sad but doing it in the stylesheet seems to break bootstrap -->
|
54
|
+
<div class="input-group" id="job_search" style="display: none;">
|
55
|
+
<input type="text" class="form-control" id="jobs_search_term" placeholder="">
|
56
|
+
<span class="input-group-btn">
|
57
|
+
<a href="" class="btn btn-default refresh_jobs_link" aria-label="Run Search">
|
58
|
+
Filter <span class="glyphicon glyphicon-filter"></span>
|
59
|
+
</a>
|
60
|
+
</span>
|
61
|
+
</div>
|
62
|
+
</div>
|
63
|
+
<div class="col-md-6">
|
64
|
+
</div>
|
65
|
+
<div class="col-md-1">
|
66
|
+
<a href="" class="btn btn-default pull-right refresh_jobs_link" aria-label="Refresh Jobs Table">
|
67
|
+
<span class="glyphicon glyphicon-refresh"></span> Refresh
|
68
|
+
</a>
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
</div>
|
72
|
+
|
73
|
+
<div class="row job-list-row">
|
74
|
+
<div class="col-md-12">
|
75
|
+
<table id="jobs" class="table table-striped table-bordered">
|
76
|
+
<thead>
|
77
|
+
<tr>
|
78
|
+
<th>ID</th>
|
79
|
+
<th>Tag</th>
|
80
|
+
<th>Attempt</th>
|
81
|
+
<th>Priority</th>
|
82
|
+
<th>Strand</th>
|
83
|
+
<th>Run At</th>
|
84
|
+
</tr>
|
85
|
+
</thead>
|
86
|
+
<tbody>
|
87
|
+
</tbody>
|
88
|
+
</table>
|
89
|
+
</div>
|
90
|
+
</div>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<script type="text/javascript" charset="utf8">
|
8
|
+
window.ENV = <%= render_javascript_env %>
|
9
|
+
</script>
|
10
|
+
<script type="text/javascript" charset="utf8 "src="//code.jquery.com/jquery-2.1.3.min.js" defer></script>
|
11
|
+
<script type="text/javascript" charset="utf8" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" defer></script>
|
12
|
+
<script type="text/javascript" charset="utf8" src="//cdn.datatables.net/1.10.6/js/jquery.dataTables.js" defer></script>
|
13
|
+
<script type="text/javascript" charset="utf8" src="//cdn.datatables.net/plug-ins/1.10.6/integration/bootstrap/3/dataTables.bootstrap.js" defer></script>
|
14
|
+
<script type="text/javascript" charset="utf8" src="<%= url_path 'js/app.js' %>" defer></script>
|
15
|
+
|
16
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
|
17
|
+
<link rel="stylesheet" href="//cdn.datatables.net/plug-ins/1.10.6/integration/bootstrap/3/dataTables.bootstrap.css">
|
18
|
+
<link rel="stylesheet" href="<%= url_path 'css/app.css' %>">
|
19
|
+
|
20
|
+
<title>Delayed Jobs</title>
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
<nav class="navbar navbar-default">
|
24
|
+
<div class="container-fluid">
|
25
|
+
<!-- Brand and toggle get grouped for better mobile display -->
|
26
|
+
<div class="navbar-header">
|
27
|
+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
28
|
+
<span class="sr-only">Toggle navigation</span>
|
29
|
+
<span class="icon-bar"></span>
|
30
|
+
<span class="icon-bar"></span>
|
31
|
+
<span class="icon-bar"></span>
|
32
|
+
</button>
|
33
|
+
<a class="navbar-brand" href="<%= url_path '/' %>">Delayed Jobs</a>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<!-- Collect the nav links, forms, and other content for toggling -->
|
37
|
+
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
38
|
+
<ul class="nav navbar-nav">
|
39
|
+
</ul>
|
40
|
+
</div><!-- /.navbar-collapse -->
|
41
|
+
</div><!-- /.container-fluid -->
|
42
|
+
</nav>
|
43
|
+
<div class="container">
|
44
|
+
<%= yield %>
|
45
|
+
</div>
|
46
|
+
</body>
|
47
|
+
</html>
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/json'
|
3
|
+
require 'json'
|
4
|
+
require 'delayed_job'
|
5
|
+
|
6
|
+
module Delayed
|
7
|
+
class Server < Sinatra::Base
|
8
|
+
APP_DIR = File.dirname(File.expand_path(__FILE__))
|
9
|
+
set :views, File.join(APP_DIR, 'server', 'views')
|
10
|
+
set :public_folder, File.join(APP_DIR, 'server', 'public')
|
11
|
+
|
12
|
+
def initialize(*args, &block)
|
13
|
+
super()
|
14
|
+
# Rails will take care of establishing the DB connection for us if there is
|
15
|
+
# an application present
|
16
|
+
if using_active_record? && !ActiveRecord::Base.connected?
|
17
|
+
ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def using_active_record?
|
22
|
+
Delayed::Job == Delayed::Backend::ActiveRecord::Job
|
23
|
+
end
|
24
|
+
|
25
|
+
# Ensure we're connected to the DB before processing the request
|
26
|
+
before do
|
27
|
+
if ActiveRecord::Base.respond_to?(:verify_active_connections!) && using_active_record?
|
28
|
+
ActiveRecord::Base.verify_active_connections!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Release any used connections back to the pool
|
33
|
+
after do
|
34
|
+
ActiveRecord::Base.clear_active_connections! if using_active_record?
|
35
|
+
end
|
36
|
+
|
37
|
+
configure :development do
|
38
|
+
require 'sinatra/reloader'
|
39
|
+
register Sinatra::Reloader
|
40
|
+
end
|
41
|
+
|
42
|
+
helpers do
|
43
|
+
# this can't get required until the class has been opened for the first time
|
44
|
+
require 'delayed/server/helpers'
|
45
|
+
include Delayed::Server::Helpers
|
46
|
+
end
|
47
|
+
|
48
|
+
get '/' do
|
49
|
+
erb :index
|
50
|
+
end
|
51
|
+
|
52
|
+
get '/running' do
|
53
|
+
content_type :json
|
54
|
+
json({
|
55
|
+
draw: params['draw'].to_i,
|
56
|
+
recordsTotal: Delayed::Job.running.count,
|
57
|
+
recordsFiltered: Delayed::Job.running.count,
|
58
|
+
data: Delayed::Job.running_jobs.map{ |j|
|
59
|
+
j.as_json(include_root: false, except: [:handler, :last_error])
|
60
|
+
},
|
61
|
+
})
|
62
|
+
end
|
63
|
+
|
64
|
+
get '/tags' do
|
65
|
+
content_type :json
|
66
|
+
json({
|
67
|
+
draw: params['draw'].to_i,
|
68
|
+
data: Delayed::Job.tag_counts('current', 10)
|
69
|
+
})
|
70
|
+
end
|
71
|
+
|
72
|
+
DEFAULT_PAGE_SIZE = 10
|
73
|
+
MAX_PAGE_SIZE = 100
|
74
|
+
get '/jobs' do
|
75
|
+
content_type :json
|
76
|
+
flavor = params['flavor'] || 'current'
|
77
|
+
page_size = extract_page_size
|
78
|
+
offset = Integer(params['start'] || 0)
|
79
|
+
case flavor
|
80
|
+
when 'id'
|
81
|
+
jobs = Delayed::Job.where(id: params['search_term'])
|
82
|
+
total_records = 1
|
83
|
+
when 'future', 'current', 'failed'
|
84
|
+
jobs = Delayed::Job.list_jobs(flavor, page_size, offset)
|
85
|
+
total_records = Delayed::Job.jobs_count(flavor)
|
86
|
+
else
|
87
|
+
query = params['search_term']
|
88
|
+
if query.present?
|
89
|
+
jobs = Delayed::Job.list_jobs(flavor, page_size, offset, query)
|
90
|
+
else
|
91
|
+
jobs = []
|
92
|
+
end
|
93
|
+
total_records = Delayed::Job.jobs_count(flavor, query)
|
94
|
+
end
|
95
|
+
json({
|
96
|
+
draw: params['draw'].to_i,
|
97
|
+
recordsTotal: total_records,
|
98
|
+
recordsFiltered: jobs.size,
|
99
|
+
data: build_jobs_json(jobs),
|
100
|
+
})
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def extract_page_size
|
106
|
+
page_size = Integer(params['length'] || DEFAULT_PAGE_SIZE)
|
107
|
+
# if dataTables wants all of the records it will send us -1 but we don't
|
108
|
+
# want the potential to kill our servers with this request so we'll limit it
|
109
|
+
page_size = DEFAULT_PAGE_SIZE if page_size == -1
|
110
|
+
[page_size, MAX_PAGE_SIZE].min
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def build_jobs_json(jobs)
|
115
|
+
json = jobs.map{ |j|
|
116
|
+
j.as_json(root: false, except: [:handler, :last_error])
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Delayed
|
5
|
+
module Settings
|
6
|
+
SETTINGS = [
|
7
|
+
:queue,
|
8
|
+
:max_attempts,
|
9
|
+
:sleep_delay,
|
10
|
+
:sleep_delay_stagger,
|
11
|
+
:fetch_batch_size,
|
12
|
+
:select_random_from_batch,
|
13
|
+
:worker_procname_prefix,
|
14
|
+
:pool_procname_suffix,
|
15
|
+
:default_job_options,
|
16
|
+
:silence_periodic_log,
|
17
|
+
:disable_periodic_jobs,
|
18
|
+
:disable_automatic_orphan_unlocking,
|
19
|
+
:last_ditch_logfile,
|
20
|
+
:parent_process_client_timeout,
|
21
|
+
]
|
22
|
+
SETTINGS_WITH_ARGS = [ :num_strands ]
|
23
|
+
|
24
|
+
SETTINGS.each do |setting|
|
25
|
+
mattr_writer(setting)
|
26
|
+
self.send("#{setting}=", nil)
|
27
|
+
define_singleton_method(setting) do
|
28
|
+
val = class_variable_get(:"@@#{setting}")
|
29
|
+
val.respond_to?(:call) ? val.call() : val
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
mattr_accessor(*SETTINGS_WITH_ARGS)
|
34
|
+
|
35
|
+
def self.queue=(queue_name)
|
36
|
+
raise(ArgumentError, "queue_name must not be blank") if queue_name.blank?
|
37
|
+
@@queue = queue_name
|
38
|
+
end
|
39
|
+
|
40
|
+
self.queue = "queue"
|
41
|
+
self.max_attempts = 1
|
42
|
+
self.sleep_delay = 2.0
|
43
|
+
self.sleep_delay_stagger = 2.0
|
44
|
+
self.fetch_batch_size = 5
|
45
|
+
self.select_random_from_batch = false
|
46
|
+
self.silence_periodic_log = false
|
47
|
+
self.parent_process_client_timeout = 10.0
|
48
|
+
|
49
|
+
self.num_strands = ->(strand_name){ nil }
|
50
|
+
self.default_job_options = ->{ Hash.new }
|
51
|
+
|
52
|
+
def self.worker_config(config_filename = nil)
|
53
|
+
config_filename ||= default_worker_config_name
|
54
|
+
config = YAML.load(ERB.new(File.read(config_filename)).result)
|
55
|
+
env = defined?(RAILS_ENV) ? RAILS_ENV : ENV['RAILS_ENV'] || 'development'
|
56
|
+
config = config[env] || config['default']
|
57
|
+
# Backwards compatibility from when the config was just an array of queues
|
58
|
+
config = { :workers => config } if config.is_a?(Array)
|
59
|
+
unless config && config.is_a?(Hash)
|
60
|
+
raise ArgumentError,
|
61
|
+
"Invalid config file #{config_filename}"
|
62
|
+
end
|
63
|
+
config = config.with_indifferent_access
|
64
|
+
config[:workers].map! do |worker_config|
|
65
|
+
config.except(:workers).merge(worker_config.with_indifferent_access)
|
66
|
+
end
|
67
|
+
config
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.apply_worker_config!(config)
|
71
|
+
SETTINGS.each do |setting|
|
72
|
+
self.send("#{setting}=", config[setting.to_s]) if config.key?(setting.to_s)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.default_worker_config_name
|
77
|
+
expand_rails_path("config/delayed_jobs.yml")
|
78
|
+
end
|
79
|
+
|
80
|
+
# Expands rails-relative paths, without depending on rails being loaded.
|
81
|
+
def self.expand_rails_path(path)
|
82
|
+
root = if defined?(Rails) && Rails.root
|
83
|
+
(Rails.root+"Gemfile").to_s
|
84
|
+
else
|
85
|
+
ENV.fetch('BUNDLE_GEMFILE')
|
86
|
+
end
|
87
|
+
File.expand_path("../#{path}", root)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Delayed
|
2
|
+
module Testing
|
3
|
+
def self.run_job(job)
|
4
|
+
Delayed::Worker.new.perform(job)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.drain
|
8
|
+
while job = Delayed::Job.get_and_lock_next_available(
|
9
|
+
'spec run_jobs',
|
10
|
+
Delayed::Settings.queue,
|
11
|
+
0,
|
12
|
+
Delayed::MAX_PRIORITY)
|
13
|
+
run_job(job)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.track_created
|
18
|
+
job_tracking = JobTracking.track { yield }
|
19
|
+
job_tracking.created
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.clear_all!
|
23
|
+
case Delayed::Job.name
|
24
|
+
when /Redis/
|
25
|
+
Delayed::Job.redis.flushdb
|
26
|
+
when /ActiveRecord/
|
27
|
+
Delayed::Job.delete_all
|
28
|
+
Delayed::Job::Failed.delete_all
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Delayed
|
2
|
+
module WorkQueue
|
3
|
+
# The simplest possible implementation of a WorkQueue -- just turns around and
|
4
|
+
# queries the queue inline.
|
5
|
+
class InProcess
|
6
|
+
def get_and_lock_next_available(worker_name, queue_name, min_priority, max_priority)
|
7
|
+
Delayed::Worker.lifecycle.run_callbacks(:work_queue_pop, self) do
|
8
|
+
Delayed::Job.get_and_lock_next_available(worker_name, queue_name, min_priority, max_priority)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|