rest-ftp-daemon 0.243.2 → 0.245
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/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
|