rest-ftp-daemon 0.243.2 → 0.245
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/rest-ftp-daemon/api/dashboard.rb +7 -4
- data/lib/rest-ftp-daemon/api/jobs.rb +1 -0
- data/lib/rest-ftp-daemon/constants.rb +4 -3
- data/lib/rest-ftp-daemon/job.rb +11 -1
- data/lib/rest-ftp-daemon/job_queue.rb +36 -24
- data/lib/rest-ftp-daemon/views/dashboard_jobs.haml +13 -7
- data/lib/rest-ftp-daemon/views/dashboard_table.haml +2 -0
- data/lib/rest-ftp-daemon/views/dashboard_workers.haml +2 -0
- data/lib/rest-ftp-daemon/worker.rb +5 -3
- data/lib/rest-ftp-daemon/worker_job.rb +6 -5
- data/lib/rest-ftp-daemon/worker_pool.rb +17 -14
- data/spec/rest-ftp-daemon/features/routes_spec.rb +0 -5
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9be0d61a767998e3daba2c1006ba9c8b184e303
|
4
|
+
data.tar.gz: 46b7e9173008c7f5e4cb015ae84b1d20ac788cd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fec8c694546fc1d7b2991f2d0d8e1fa2bf35669a7e6cd56dffd459b787db66ab9a608205635dce427720022b7c3b94aaade650c110674042d2cb302d0def058f
|
7
|
+
data.tar.gz: 45621e4a9a99a535c5448a5172986d391f76f396feab220efb89979ee1f0be63499b5edd1ca8012b8cae275ae7b9dff7c5997ee67c638b8d7db541219a29b528
|
data/Gemfile.lock
CHANGED
@@ -43,17 +43,20 @@ module RestFtpDaemon
|
|
43
43
|
@only = params["only"].to_s
|
44
44
|
|
45
45
|
# Get jobs for this view, order jobs by their weights
|
46
|
-
|
46
|
+
jobs_with_status = $queue.jobs_with_status(@only).reverse
|
47
47
|
|
48
48
|
# Provide queue only if no filtering set
|
49
|
-
@
|
50
|
-
|
49
|
+
if @only.empty?
|
50
|
+
@jobs_queued = $queue.jobs_queued
|
51
|
+
else
|
52
|
+
@jobs_queued = []
|
53
|
+
end
|
51
54
|
|
52
55
|
# Get workers status
|
53
56
|
@worker_variables = $pool.worker_variables
|
54
57
|
|
55
58
|
# Build paginator
|
56
|
-
@paginate = Paginate.new
|
59
|
+
@paginate = Paginate.new jobs_with_status
|
57
60
|
@paginate.only = params["only"]
|
58
61
|
@paginate.page = params["page"]
|
59
62
|
@paginate.all = params.keys.include? "all"
|
@@ -77,6 +77,7 @@ module RestFtpDaemon
|
|
77
77
|
optional :label, type: String, desc: "Descriptive label for this job"
|
78
78
|
optional :notify, type: String, desc: "URL to get POST'ed notifications back"
|
79
79
|
optional :priority, type: Integer, desc: "Priority level of the job (lower is stronger)"
|
80
|
+
optional :pool, type: String, desc: "Pool of worker to be used"
|
80
81
|
optional :overwrite,
|
81
82
|
type: Boolean,
|
82
83
|
desc: "Overwrites files at target server",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Terrific constants
|
2
2
|
APP_NAME = "rest-ftp-daemon"
|
3
3
|
APP_NICK = "rftpd"
|
4
|
-
APP_VER = "0.
|
4
|
+
APP_VER = "0.245"
|
5
5
|
|
6
6
|
# Provide default config file information
|
7
7
|
APP_LIB = File.expand_path File.dirname(__FILE__)
|
@@ -20,7 +20,8 @@ EOD
|
|
20
20
|
|
21
21
|
|
22
22
|
# Configuration defaults
|
23
|
-
DEFAULT_WORKERS = 2
|
23
|
+
# DEFAULT_WORKERS = 2
|
24
|
+
DEFAULT_POOL = "default"
|
24
25
|
DEFAULT_WORKER_TIMEOUT = 3600 # 1h
|
25
26
|
DEFAULT_SFTP_TIMEOUT = 600 # 10mn
|
26
27
|
DEFAULT_FTP_CHUNK = 1024 # 1 MB
|
@@ -91,7 +92,7 @@ DASHBOARD_JOB_STYLES = {
|
|
91
92
|
}
|
92
93
|
DASHBOARD_WORKER_STYLES = {
|
93
94
|
waiting: :success,
|
94
|
-
|
95
|
+
running: :info,
|
95
96
|
crashed: :danger,
|
96
97
|
done: :success,
|
97
98
|
dead: :danger,
|
data/lib/rest-ftp-daemon/job.rb
CHANGED
@@ -11,7 +11,7 @@ module RestFtpDaemon
|
|
11
11
|
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
12
12
|
end
|
13
13
|
|
14
|
-
FIELDS = [:source, :target, :label, :priority, :notify, :overwrite, :mkdir, :tempfile]
|
14
|
+
FIELDS = [:source, :target, :label, :priority, :pool, :notify, :overwrite, :mkdir, :tempfile]
|
15
15
|
|
16
16
|
attr_accessor :wid
|
17
17
|
|
@@ -27,6 +27,7 @@ module RestFtpDaemon
|
|
27
27
|
attr_reader :finished_at
|
28
28
|
|
29
29
|
attr_reader :infos
|
30
|
+
attr_reader :pool
|
30
31
|
|
31
32
|
FIELDS.each do |name|
|
32
33
|
attr_reader name
|
@@ -58,6 +59,15 @@ module RestFtpDaemon
|
|
58
59
|
instance_variable_set "@#{name}", params[name]
|
59
60
|
end
|
60
61
|
|
62
|
+
# Set pool
|
63
|
+
pools = (Settings.pools || {})
|
64
|
+
# Check if pool name exists
|
65
|
+
if (pools.keys.include? params[:pool])
|
66
|
+
@pool = params[:pool].to_s
|
67
|
+
else
|
68
|
+
@pool = DEFAULT_POOL
|
69
|
+
end
|
70
|
+
|
61
71
|
# Set job queue, thus reset
|
62
72
|
reset
|
63
73
|
|
@@ -5,7 +5,7 @@ module RestFtpDaemon
|
|
5
5
|
include LoggerHelper
|
6
6
|
attr_reader :logger
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
#attr_reader :queues
|
9
9
|
attr_reader :jobs
|
10
10
|
|
11
11
|
if Settings.newrelic_enabled?
|
@@ -14,11 +14,17 @@ module RestFtpDaemon
|
|
14
14
|
|
15
15
|
def initialize
|
16
16
|
# Instance variables
|
17
|
-
@
|
17
|
+
@queues = {}
|
18
|
+
@waitings = {}
|
19
|
+
|
20
|
+
# @queue = []
|
21
|
+
# @waiting = []
|
22
|
+
|
18
23
|
@jobs = []
|
19
|
-
|
20
|
-
@
|
21
|
-
@
|
24
|
+
|
25
|
+
@queues.taint # enable tainted communication
|
26
|
+
@waitings.taint
|
27
|
+
|
22
28
|
taint
|
23
29
|
@mutex = Mutex.new
|
24
30
|
|
@@ -65,7 +71,11 @@ module RestFtpDaemon
|
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
68
|
-
def
|
74
|
+
def jobs_queued
|
75
|
+
@queues
|
76
|
+
end
|
77
|
+
|
78
|
+
def jobs_with_status status
|
69
79
|
# No status filter: return all execept queued
|
70
80
|
if status.empty?
|
71
81
|
@jobs.reject { |job| job.status == JOB_STATUS_QUEUED }
|
@@ -88,7 +98,7 @@ module RestFtpDaemon
|
|
88
98
|
end
|
89
99
|
|
90
100
|
def queued_ids
|
91
|
-
@
|
101
|
+
@queues.collect{|pool, jobs| jobs.collect(&:id)}
|
92
102
|
end
|
93
103
|
|
94
104
|
def jobs_ids
|
@@ -101,7 +111,8 @@ module RestFtpDaemon
|
|
101
111
|
log_info "find_by_id (#{id}, #{prefixed}) > #{id}"
|
102
112
|
|
103
113
|
# Search in jobs queues
|
104
|
-
|
114
|
+
#@jobs.reverse.find { |item| item.id == id }
|
115
|
+
@jobs.find { |item| item.id == id }
|
105
116
|
end
|
106
117
|
|
107
118
|
|
@@ -109,24 +120,31 @@ module RestFtpDaemon
|
|
109
120
|
# Check that item responds to "priorty" method
|
110
121
|
raise "JobQueue.push: job should respond to priority method" unless job.respond_to? :priority
|
111
122
|
raise "JobQueue.push: job should respond to id method" unless job.respond_to? :id
|
123
|
+
raise "JobQueue.push: job should respond to pool method" unless job.respond_to? :pool
|
112
124
|
raise "JobQueue.push: job should respond to reset" unless job.respond_to? :reset
|
113
125
|
|
114
126
|
@mutex.synchronize do
|
127
|
+
# Get this job's pool @ prepare queue of this pool
|
128
|
+
pool = job.pool
|
129
|
+
myqueue = (@queues[pool] ||= [])
|
130
|
+
|
115
131
|
# Store the job into the global jobs list, if not already inside
|
116
132
|
@jobs.push(job) unless @jobs.include?(job)
|
117
133
|
|
118
134
|
# Push job into the queue, if not already inside
|
119
|
-
|
135
|
+
myqueue.push(job) unless myqueue.include?(job)
|
120
136
|
|
121
137
|
# Inform the job that it's been queued / reset it
|
122
138
|
job.reset
|
123
139
|
|
124
140
|
# Refresh queue order
|
125
|
-
sort_queue!
|
141
|
+
#sort_queue!(pool)
|
142
|
+
myqueue.sort_by!(&:weight)
|
126
143
|
|
127
144
|
# Try to wake a worker up
|
128
145
|
begin
|
129
|
-
|
146
|
+
@waitings[pool] ||= []
|
147
|
+
t = @waitings[pool].shift
|
130
148
|
t.wakeup if t
|
131
149
|
rescue ThreadError
|
132
150
|
retry
|
@@ -137,16 +155,18 @@ module RestFtpDaemon
|
|
137
155
|
alias enq push
|
138
156
|
alias requeue push
|
139
157
|
|
140
|
-
def pop non_block = false
|
158
|
+
def pop pool, non_block = false
|
141
159
|
@mutex.synchronize do
|
160
|
+
myqueue = (@queues[pool] ||= [])
|
161
|
+
@waitings[pool] ||= []
|
142
162
|
loop do
|
143
|
-
if
|
144
|
-
#
|
163
|
+
if myqueue.empty?
|
164
|
+
#puts "JobQueue.pop(#{pool}): empty"
|
145
165
|
raise ThreadError, "queue empty" if non_block
|
146
|
-
@
|
166
|
+
@waitings[pool].push Thread.current
|
147
167
|
@mutex.sleep
|
148
168
|
else
|
149
|
-
return
|
169
|
+
return myqueue.pop
|
150
170
|
end
|
151
171
|
end
|
152
172
|
end
|
@@ -202,19 +222,11 @@ module RestFtpDaemon
|
|
202
222
|
"#{@prefix}.#{id}"
|
203
223
|
end
|
204
224
|
|
205
|
-
def sort_queue!
|
206
|
-
@mutex_counters.synchronize do
|
207
|
-
@queue.sort_by!(&:weight)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
225
|
if Settings.newrelic_enabled?
|
212
226
|
add_transaction_tracer :push, category: :task
|
213
227
|
add_transaction_tracer :pop, category: :task
|
214
|
-
add_transaction_tracer :sort_queue!, category: :task
|
215
228
|
add_transaction_tracer :expire, category: :task
|
216
229
|
add_transaction_tracer :counts_by_status, category: :task
|
217
|
-
add_transaction_tracer :filter_jobs, category: :task
|
218
230
|
end
|
219
231
|
|
220
232
|
end
|
@@ -32,6 +32,7 @@
|
|
32
32
|
%tr
|
33
33
|
%th ID
|
34
34
|
%th label
|
35
|
+
%th pool
|
35
36
|
%th source
|
36
37
|
%th mode
|
37
38
|
%th target
|
@@ -44,15 +45,20 @@
|
|
44
45
|
%th{title: "Priority"} P
|
45
46
|
%th{title: "Runs count"} R
|
46
47
|
|
47
|
-
- unless @queue.empty?
|
48
|
-
%tbody.jobs
|
49
|
-
= render :dashboard_table, {jobs: @queue}
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
- @jobs_queued.each do |pool, jobs|
|
50
|
+
- unless jobs.empty?
|
51
|
+
%tbody.jobs
|
52
|
+
= render :dashboard_table, {jobs: jobs}
|
53
|
+
|
54
|
+
%thead
|
55
|
+
%tr
|
56
|
+
%td{colspan: 14}
|
57
|
+
%br
|
55
58
|
|
56
59
|
- unless jobs.empty?
|
57
60
|
%tbody.jobs
|
58
61
|
= render :dashboard_table, {jobs: jobs}
|
62
|
+
|
63
|
+
|
64
|
+
|
@@ -7,15 +7,17 @@ module RestFtpDaemon
|
|
7
7
|
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
8
8
|
end
|
9
9
|
|
10
|
-
def initialize wid
|
10
|
+
def initialize wid, pool = nil
|
11
11
|
# Logger
|
12
12
|
@logger = RestFtpDaemon::LoggerPool.instance.get :workers
|
13
13
|
@log_worker_status_changes = true
|
14
14
|
|
15
15
|
# Worker name
|
16
|
-
|
16
|
+
#@wid = wid
|
17
|
+
@pool = pool
|
17
18
|
|
18
19
|
# Set thread context
|
20
|
+
Thread.current.thread_variable_set :pool, pool
|
19
21
|
Thread.current.thread_variable_set :wid, wid
|
20
22
|
Thread.current.thread_variable_set :started_at, Time.now
|
21
23
|
worker_status WORKER_STATUS_STARTING
|
@@ -25,7 +27,7 @@ module RestFtpDaemon
|
|
25
27
|
|
26
28
|
def log_context
|
27
29
|
{
|
28
|
-
wid:
|
30
|
+
wid: Thread.current.thread_variable_get(:wid),
|
29
31
|
jid: Thread.current.thread_variable_get(:jid),
|
30
32
|
}
|
31
33
|
end
|
@@ -2,8 +2,9 @@ module RestFtpDaemon
|
|
2
2
|
|
3
3
|
# Worker used to process Jobs
|
4
4
|
class JobWorker < Worker
|
5
|
+
#attr_reader :pool
|
5
6
|
|
6
|
-
def initialize wid
|
7
|
+
def initialize wid, pool
|
7
8
|
# Generic worker initialize
|
8
9
|
super
|
9
10
|
|
@@ -11,7 +12,7 @@ module RestFtpDaemon
|
|
11
12
|
@timeout = (Settings.transfer.timeout rescue nil) || DEFAULT_WORKER_TIMEOUT
|
12
13
|
|
13
14
|
# Start main loop
|
14
|
-
log_info "JobWorker
|
15
|
+
log_info "JobWorker initializing", ["wid: #{wid}", "pool: #{pool}", "timeout: #{@timeout}"]
|
15
16
|
start
|
16
17
|
end
|
17
18
|
|
@@ -20,14 +21,14 @@ module RestFtpDaemon
|
|
20
21
|
def work
|
21
22
|
# Wait for a job to be available in the queue
|
22
23
|
worker_status WORKER_STATUS_WAITING
|
23
|
-
job = $queue.pop
|
24
|
+
job = $queue.pop @pool
|
24
25
|
|
25
26
|
# Work on this job
|
26
27
|
work_on_job(job)
|
27
28
|
|
28
|
-
# Clean job status
|
29
|
+
# Clean job status
|
29
30
|
job.wid = nil
|
30
|
-
sleep 1
|
31
|
+
#sleep 1
|
31
32
|
|
32
33
|
# If job status requires a retry, just restack it
|
33
34
|
on_errors = Settings.at(:retry, :on_errors)
|
@@ -4,7 +4,6 @@ module RestFtpDaemon
|
|
4
4
|
class WorkerPool
|
5
5
|
include LoggerHelper
|
6
6
|
attr_reader :logger
|
7
|
-
|
8
7
|
attr_reader :wid
|
9
8
|
|
10
9
|
if Settings.newrelic_enabled?
|
@@ -53,34 +52,38 @@ module RestFtpDaemon
|
|
53
52
|
|
54
53
|
def create_threads
|
55
54
|
# Read configuration
|
56
|
-
|
55
|
+
pools = (Settings.pools || {})
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
# Minimum one worker on DEFAULT_POOL
|
58
|
+
if !(pools.is_a? Hash)
|
59
|
+
log_error "create_threads: one worker is the minimum possible number (#{pools.inspect}"
|
61
60
|
end
|
61
|
+
pools[DEFAULT_POOL] ||= 1
|
62
62
|
|
63
63
|
# Create workers
|
64
|
-
log_info "WorkerPool creating #{
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
64
|
+
log_info "WorkerPool creating JobWorker's #{pools.inspect} + ConchitaWorker"
|
65
|
+
pools.each do |pool, count|
|
66
|
+
# Start worker threads for each pool
|
67
|
+
log_info "WorkerPool creating JobWorker [#{pool}] x#{count}"
|
68
|
+
count.times do
|
69
|
+
wid = generate_id
|
70
|
+
@workers[wid] = create_worker_thread wid, pool
|
71
|
+
end
|
70
72
|
end
|
71
73
|
|
72
74
|
# Start conchita thread
|
75
|
+
log_info "WorkerPool creating ConchitaWorker"
|
73
76
|
@conchita = create_conchita_thread
|
74
77
|
|
75
78
|
rescue StandardError => ex
|
76
79
|
log_error "UNHANDLED EXCEPTION: #{ex.message}", ex.backtrace
|
77
80
|
end
|
78
81
|
|
79
|
-
def create_worker_thread wid
|
82
|
+
def create_worker_thread wid, pool
|
80
83
|
Thread.new wid do
|
81
84
|
begin
|
82
|
-
worker = JobWorker.new wid
|
83
|
-
log_info "JobWorker [#{wid}]: #{worker}"
|
85
|
+
worker = JobWorker.new wid, pool
|
86
|
+
log_info "JobWorker [#{wid}][#{pool}]: #{worker}"
|
84
87
|
rescue StandardError => ex
|
85
88
|
log_error "JobWorker EXCEPTION: #{ex.message}"
|
86
89
|
end
|
@@ -10,11 +10,6 @@ describe "Routes", feature: true do
|
|
10
10
|
expect(response.status).to eq 200
|
11
11
|
end
|
12
12
|
|
13
|
-
it "exposes properly formed JSON" do
|
14
|
-
expect { JSON.parse(response.to_s) }.not_to raise_error
|
15
|
-
expect(JSON.parse(response.to_s)).to all(have_key("options"))
|
16
|
-
end
|
17
|
-
|
18
13
|
end # GET /
|
19
14
|
|
20
15
|
end
|