qpush 0.1.4 → 0.1.6
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/.byebug_history +43 -0
- data/README.md +4 -4
- data/bin/console +1 -0
- data/jobs/fail_job.rb +1 -1
- data/jobs/test_job.rb +1 -1
- data/lib/qpush.rb +2 -2
- data/lib/qpush/base.rb +7 -5
- data/lib/qpush/base/config.rb +41 -0
- data/lib/qpush/{job.rb → base/job.rb} +4 -23
- data/lib/qpush/base/redis.rb +13 -0
- data/lib/qpush/client.rb +7 -0
- data/lib/qpush/client/config.rb +13 -0
- data/lib/qpush/client/job.rb +12 -0
- data/lib/qpush/client/redis.rb +16 -0
- data/lib/qpush/jobs/queue_delayed.rb +0 -2
- data/lib/qpush/server.rb +10 -7
- data/lib/qpush/server/apis.rb +10 -0
- data/lib/qpush/server/apis/delay.rb +5 -3
- data/lib/qpush/server/apis/execute.rb +0 -4
- data/lib/qpush/server/apis/fail.rb +2 -2
- data/lib/qpush/server/apis/history.rb +3 -3
- data/lib/qpush/server/apis/morgue.rb +3 -7
- data/lib/qpush/server/apis/perform.rb +3 -7
- data/lib/qpush/server/apis/queue.rb +3 -7
- data/lib/qpush/server/apis/setup.rb +1 -5
- data/lib/qpush/server/apis/success.rb +3 -7
- data/lib/qpush/server/config.rb +49 -0
- data/lib/qpush/server/database.rb +1 -1
- data/lib/qpush/server/delay.rb +4 -4
- data/lib/qpush/server/heartbeat.rb +3 -3
- data/lib/qpush/server/jobs.rb +12 -1
- data/lib/qpush/server/launcher.rb +3 -3
- data/lib/qpush/server/loader.rb +7 -7
- data/lib/qpush/server/manager.rb +21 -11
- data/lib/qpush/server/perform.rb +1 -2
- data/lib/qpush/server/queue.rb +1 -1
- data/lib/qpush/server/redis.rb +48 -0
- data/lib/qpush/server/worker.rb +57 -23
- data/lib/qpush/version.rb +1 -1
- data/lib/qpush/web/apis/create.rb +16 -0
- data/lib/qpush/web/apis/crons.rb +1 -1
- data/lib/qpush/web/apis/heart.rb +1 -1
- data/lib/qpush/web/apis/history.rb +1 -1
- data/lib/qpush/web/apis/jobs.rb +1 -1
- data/lib/qpush/web/apis/morgue.rb +1 -1
- data/lib/qpush/web/apis/queue_delayed.rb +1 -1
- data/lib/qpush/web/apis/retries.rb +1 -1
- data/lib/qpush/web/apis/stats.rb +2 -2
- data/lib/qpush/web/config.rb +13 -0
- data/lib/qpush/web/get.rb +0 -8
- data/lib/qpush/web/post.rb +7 -3
- data/lib/qpush/web/public/app/shared/navbar/assets/logo.png +0 -0
- data/lib/qpush/web/public/assets/data.json +6 -0
- data/lib/qpush/web/public/assets/svg/more.svg +7 -0
- data/lib/qpush/web/public/css/main.css +1 -0
- data/lib/qpush/web/public/fonts/icons.eot +0 -0
- data/lib/qpush/web/public/fonts/icons.otf +0 -0
- data/lib/qpush/web/public/fonts/icons.svg +685 -0
- data/lib/qpush/web/public/fonts/icons.ttf +0 -0
- data/lib/qpush/web/public/fonts/icons.woff +0 -0
- data/lib/qpush/web/public/fonts/icons.woff2 +0 -0
- data/lib/qpush/web/public/index.html +40 -0
- data/lib/qpush/web/public/js/app.js +52 -0
- data/lib/qpush/web/public/js/shims.js +15 -0
- data/lib/qpush/web/public/tsconfig.json +20 -0
- data/lib/qpush/web/redis.rb +16 -0
- data/lib/qpush/web/server.rb +9 -5
- data/qpush.gemspec +1 -0
- metadata +42 -5
- data/lib/qpush/config.rb +0 -63
- data/lib/qpush/redis.rb +0 -53
@@ -2,10 +2,6 @@ module QPush
|
|
2
2
|
module Server
|
3
3
|
module Apis
|
4
4
|
class Morgue < Base
|
5
|
-
def initialize(job)
|
6
|
-
@job = job
|
7
|
-
end
|
8
|
-
|
9
5
|
def call
|
10
6
|
send_to_morgue
|
11
7
|
end
|
@@ -13,9 +9,9 @@ module QPush
|
|
13
9
|
private
|
14
10
|
|
15
11
|
def send_to_morgue
|
16
|
-
|
17
|
-
conn.hincrby(
|
18
|
-
conn.lpush(
|
12
|
+
Server.redis do |conn|
|
13
|
+
conn.hincrby(Server.keys.stats, 'dead', 1)
|
14
|
+
conn.lpush(Server.keys.morgue, @job.to_json)
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -2,10 +2,6 @@ module QPush
|
|
2
2
|
module Server
|
3
3
|
module Apis
|
4
4
|
class Perform < Base
|
5
|
-
def initialize(job)
|
6
|
-
@job = job
|
7
|
-
end
|
8
|
-
|
9
5
|
def call
|
10
6
|
perform_job
|
11
7
|
end
|
@@ -13,9 +9,9 @@ module QPush
|
|
13
9
|
private
|
14
10
|
|
15
11
|
def perform_job
|
16
|
-
|
17
|
-
conn.hincrby(
|
18
|
-
conn.lpush("#{
|
12
|
+
Server.redis do |conn|
|
13
|
+
conn.hincrby(Server.keys.stats, 'performed', 1)
|
14
|
+
conn.lpush("#{Server.keys.perform}:#{@job.priority}", @job.to_json)
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -2,10 +2,6 @@ module QPush
|
|
2
2
|
module Server
|
3
3
|
module Apis
|
4
4
|
class Queue < Base
|
5
|
-
def initialize(job)
|
6
|
-
@job = job
|
7
|
-
end
|
8
|
-
|
9
5
|
def call
|
10
6
|
queue_job
|
11
7
|
end
|
@@ -13,9 +9,9 @@ module QPush
|
|
13
9
|
private
|
14
10
|
|
15
11
|
def queue_job
|
16
|
-
|
17
|
-
conn.hincrby(
|
18
|
-
conn.lpush(
|
12
|
+
Server.redis do |conn|
|
13
|
+
conn.hincrby(Server.keys.stats, 'queued', 1)
|
14
|
+
conn.lpush(Server.keys.queue, @job.to_json)
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -2,10 +2,6 @@ module QPush
|
|
2
2
|
module Server
|
3
3
|
module Apis
|
4
4
|
class Setup < Base
|
5
|
-
def initialize(job)
|
6
|
-
@job = job
|
7
|
-
end
|
8
|
-
|
9
5
|
def call
|
10
6
|
invalid_job && return unless @job.valid?
|
11
7
|
setup_job
|
@@ -19,7 +15,7 @@ module QPush
|
|
19
15
|
end
|
20
16
|
|
21
17
|
def invalid_job
|
22
|
-
Server.log.err("Job INVALID | #{@job.klass} | #{@job.id} | #{@job.errors.full_messages.join(' ')}")
|
18
|
+
Server.log.err("Worker #{Server.worker.id} | Job INVALID | #{@job.klass} | #{@job.id} | #{@job.errors.full_messages.join(' ')}")
|
23
19
|
end
|
24
20
|
end
|
25
21
|
end
|
@@ -2,10 +2,6 @@ module QPush
|
|
2
2
|
module Server
|
3
3
|
module Apis
|
4
4
|
class Success < Base
|
5
|
-
def initialize(job)
|
6
|
-
@job = job
|
7
|
-
end
|
8
|
-
|
9
5
|
def call
|
10
6
|
update_job
|
11
7
|
stat_increment
|
@@ -21,13 +17,13 @@ module QPush
|
|
21
17
|
end
|
22
18
|
|
23
19
|
def stat_increment
|
24
|
-
|
25
|
-
c.hincrby(
|
20
|
+
Server.redis do |c|
|
21
|
+
c.hincrby(Server.keys.stats, 'success', 1)
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
29
25
|
def log_success
|
30
|
-
Server.log.info("Job SUCCESS | #{@job.klass} with ID: #{@job.id} | #{@job.run_time}")
|
26
|
+
Server.log.info("Worker #{Server.worker.id} | Job SUCCESS | #{@job.klass} with ID: #{@job.id} | #{@job.run_time}")
|
31
27
|
end
|
32
28
|
|
33
29
|
def update_history
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module QPush
|
2
|
+
module Server
|
3
|
+
include QPush::Base::ConfigHelper
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :worker, :keys
|
7
|
+
|
8
|
+
def config
|
9
|
+
@config ||= Config.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class WorkerConfig
|
14
|
+
DEFAULTS = {
|
15
|
+
namespace: 'default',
|
16
|
+
priorities: 5,
|
17
|
+
queue_threads: 2,
|
18
|
+
perform_threads: 2,
|
19
|
+
delay_threads: 1 }.freeze
|
20
|
+
|
21
|
+
attr_accessor :perform_threads, :queue_threads, :delay_threads,
|
22
|
+
:namespace, :priorities
|
23
|
+
|
24
|
+
def initialize(options = {})
|
25
|
+
options = DEFAULTS.merge(options)
|
26
|
+
options.each { |key, value| send("#{key}=", value) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def for_keys
|
30
|
+
{ namespace: @namespace, priorities: @priorities }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Config < QPush::Base::Config
|
35
|
+
SERVER_DEFAULTS = {
|
36
|
+
database_url: ENV['DATABASE_URL'],
|
37
|
+
database_pool: 10,
|
38
|
+
jobs_path: '/jobs',
|
39
|
+
workers: [WorkerConfig.new] }.freeze
|
40
|
+
|
41
|
+
attr_accessor :database_url, :database_pool, :jobs_path, :workers
|
42
|
+
|
43
|
+
def initialize
|
44
|
+
super
|
45
|
+
SERVER_DEFAULTS.each { |key, value| send("#{key}=", value) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/qpush/server/delay.rb
CHANGED
@@ -14,7 +14,7 @@ module QPush
|
|
14
14
|
#
|
15
15
|
def start
|
16
16
|
until @done
|
17
|
-
|
17
|
+
Server.redis do |conn|
|
18
18
|
@conn = conn
|
19
19
|
watch_delay { retrieve_delays }
|
20
20
|
end
|
@@ -34,7 +34,7 @@ module QPush
|
|
34
34
|
# If any are found, begin to update them.
|
35
35
|
#
|
36
36
|
def retrieve_delays
|
37
|
-
delays = @conn.zrangebyscore(
|
37
|
+
delays = @conn.zrangebyscore(Server.keys.delay, 0, Time.now.to_i)
|
38
38
|
delays.any? ? update_delays(delays) : @conn.unwatch
|
39
39
|
end
|
40
40
|
|
@@ -42,7 +42,7 @@ module QPush
|
|
42
42
|
#
|
43
43
|
def update_delays(delays)
|
44
44
|
@conn.multi do |multi|
|
45
|
-
multi.zrem(
|
45
|
+
multi.zrem(Server.keys.delay, delays)
|
46
46
|
delays.each { |job| perform_job(job) }
|
47
47
|
end
|
48
48
|
end
|
@@ -59,7 +59,7 @@ module QPush
|
|
59
59
|
# Performs a watch on our delay list
|
60
60
|
#
|
61
61
|
def watch_delay
|
62
|
-
@conn.watch(
|
62
|
+
@conn.watch(Server.keys.delay) do
|
63
63
|
yield if block_given?
|
64
64
|
end
|
65
65
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module QPush
|
2
2
|
module Server
|
3
|
-
# The Heartbeat worker periodically updates the heart
|
3
|
+
# The Heartbeat worker periodically updates the heart key.
|
4
4
|
# The key is set with an expiry. This helps to indicate if the QPush server
|
5
5
|
# is currently active.
|
6
6
|
#
|
@@ -9,11 +9,11 @@ module QPush
|
|
9
9
|
@done = false
|
10
10
|
end
|
11
11
|
|
12
|
-
# Starts our
|
12
|
+
# Starts our heartbeat process. This will run until instructed to stop.
|
13
13
|
#
|
14
14
|
def start
|
15
15
|
until @done
|
16
|
-
|
16
|
+
Server.redis { |c| c.setex(Server.keys.heart, 30, true) }
|
17
17
|
sleep 15
|
18
18
|
end
|
19
19
|
end
|
data/lib/qpush/server/jobs.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
module QPush
|
2
2
|
module Server
|
3
|
+
module JobRegister
|
4
|
+
def included(base)
|
5
|
+
_register_job(base)
|
6
|
+
end
|
7
|
+
|
8
|
+
def _register_job(base)
|
9
|
+
Server.redis { |c| c.sadd(QPush::Base::KEY + ':jobs', base.name) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
3
13
|
module JobHelpers
|
4
14
|
def mark_success
|
5
15
|
@failed = false
|
@@ -46,12 +56,13 @@ module QPush
|
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
49
|
-
class Job < QPush::Job
|
59
|
+
class Job < QPush::Base::Job
|
50
60
|
extend Forwardable
|
51
61
|
|
52
62
|
include QPush::Server::JobHelpers
|
53
63
|
include ObjectValidator::Validate
|
54
64
|
|
65
|
+
|
55
66
|
def initialize(options)
|
56
67
|
super
|
57
68
|
@api = ApiWrapper.new(self)
|
@@ -27,7 +27,7 @@ module QPush
|
|
27
27
|
#
|
28
28
|
def setup_options
|
29
29
|
parser = OptionParser.new do |o|
|
30
|
-
o.banner = 'Usage: bundle exec
|
30
|
+
o.banner = 'Usage: bundle exec qpush-server [options]'
|
31
31
|
|
32
32
|
o.on('-c', '--config PATH', 'Load PATH for config file') do |arg|
|
33
33
|
load(arg)
|
@@ -42,11 +42,11 @@ module QPush
|
|
42
42
|
# Requires all base jobs as well as user jobs.
|
43
43
|
#
|
44
44
|
def setup_jobs
|
45
|
-
|
45
|
+
JobLoader.call
|
46
46
|
end
|
47
47
|
|
48
48
|
def boot_manager
|
49
|
-
manager = Manager.new(
|
49
|
+
manager = Manager.new(Server.config.workers)
|
50
50
|
manager.start
|
51
51
|
end
|
52
52
|
end
|
data/lib/qpush/server/loader.rb
CHANGED
@@ -3,18 +3,18 @@ module QPush
|
|
3
3
|
# The Loader will 'require' all jobs within the users job folder.
|
4
4
|
# The job folder is specified in the config.
|
5
5
|
#
|
6
|
-
class
|
6
|
+
class JobLoader
|
7
7
|
# Provides a shortend caller.
|
8
8
|
#
|
9
9
|
def self.call
|
10
|
-
|
11
|
-
|
10
|
+
loader = new
|
11
|
+
loader.call
|
12
12
|
end
|
13
13
|
|
14
14
|
# Entrypoint to load all jobs.
|
15
15
|
#
|
16
16
|
def call
|
17
|
-
|
17
|
+
flush_jobs
|
18
18
|
load_jobs
|
19
19
|
end
|
20
20
|
|
@@ -22,14 +22,14 @@ module QPush
|
|
22
22
|
|
23
23
|
# Removes old jobs from the redis job list.
|
24
24
|
#
|
25
|
-
def
|
26
|
-
|
25
|
+
def flush_jobs
|
26
|
+
Server.redis { |c| c.del(QPush::Base::KEY + ':jobs') }
|
27
27
|
end
|
28
28
|
|
29
29
|
# Requires user jobs that are specified from the config.
|
30
30
|
#
|
31
31
|
def load_jobs
|
32
|
-
Dir[Dir.pwd + "#{
|
32
|
+
Dir[Dir.pwd + "#{Server.config.jobs_path}/**/*.rb"].each do |file|
|
33
33
|
require file
|
34
34
|
end
|
35
35
|
end
|
data/lib/qpush/server/manager.rb
CHANGED
@@ -6,11 +6,11 @@ module QPush
|
|
6
6
|
class Manager
|
7
7
|
include ObjectValidator::Validate
|
8
8
|
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :configs
|
10
10
|
attr_reader :forks
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
|
12
|
+
def initialize(configs)
|
13
|
+
@configs = configs
|
14
14
|
@master = Process.pid
|
15
15
|
@forks = []
|
16
16
|
at_exit { shutdown }
|
@@ -23,6 +23,7 @@ module QPush
|
|
23
23
|
def start
|
24
24
|
validate!
|
25
25
|
start_messages
|
26
|
+
flush_spaces
|
26
27
|
create_workers
|
27
28
|
Process.wait
|
28
29
|
end
|
@@ -31,8 +32,9 @@ module QPush
|
|
31
32
|
#
|
32
33
|
def shutdown
|
33
34
|
unless @forks.empty?
|
34
|
-
@forks.each { |w| Process.kill('
|
35
|
+
@forks.each { |w| Process.kill('QUIT', w[:pid].to_i) }
|
35
36
|
end
|
37
|
+
Process.waitall
|
36
38
|
Process.kill('SIGTERM', @master)
|
37
39
|
end
|
38
40
|
|
@@ -41,8 +43,8 @@ module QPush
|
|
41
43
|
# Create the specified number of workers and starts them
|
42
44
|
#
|
43
45
|
def create_workers
|
44
|
-
@
|
45
|
-
pid = fork { Worker.new(
|
46
|
+
@configs.each_with_index do |config, id|
|
47
|
+
pid = fork { Worker.new(id, config).start }
|
46
48
|
@forks << { id: id, pid: pid }
|
47
49
|
end
|
48
50
|
end
|
@@ -50,8 +52,7 @@ module QPush
|
|
50
52
|
# Information about the start process
|
51
53
|
#
|
52
54
|
def start_messages
|
53
|
-
Server.log.info("*
|
54
|
-
Server.log.info("* Threads: #{@options[:queue_threads]} queue, #{@options[:perform_threads]} perform, #{@options[:delay_threads]} delay")
|
55
|
+
Server.log.info("* Worker count: #{@configs.count}")
|
55
56
|
end
|
56
57
|
|
57
58
|
# Validates our data before starting our Workers. Also instantiates our
|
@@ -61,6 +62,13 @@ module QPush
|
|
61
62
|
return if valid?
|
62
63
|
fail ServerError, errors.full_messages.join(' ')
|
63
64
|
end
|
65
|
+
|
66
|
+
# Removes the list of namespaces used by our server from Redis. This
|
67
|
+
# prepares it for the new list that will be created by our workers.
|
68
|
+
#
|
69
|
+
def flush_spaces
|
70
|
+
Server.redis { |c| c.del(QPush::Base::KEY + ':namespaces') }
|
71
|
+
end
|
64
72
|
end
|
65
73
|
|
66
74
|
# The ManagerValidator ensures the data for our manager is valid before
|
@@ -69,10 +77,12 @@ module QPush
|
|
69
77
|
class ManagerValidator
|
70
78
|
include ObjectValidator::Validator
|
71
79
|
|
72
|
-
validates :redis, with: { proc: proc {
|
80
|
+
validates :redis, with: { proc: proc { Server.redis { |c| c.ping && c.quit } },
|
73
81
|
msg: 'could not be connected with' }
|
74
|
-
validates :
|
75
|
-
|
82
|
+
validates :configs, with: { proc: proc { |m| m.configs.count > 0 },
|
83
|
+
msg: 'were not defined' }
|
84
|
+
validates :configs, with: { proc: proc { |m| m.configs.each { |c| c.is_a?(WorkerConfig) } },
|
85
|
+
msg: 'are not valid WorkerConfig objects' }
|
76
86
|
end
|
77
87
|
end
|
78
88
|
end
|
data/lib/qpush/server/perform.rb
CHANGED
@@ -6,7 +6,6 @@ module QPush
|
|
6
6
|
class Perform
|
7
7
|
def initialize
|
8
8
|
@done = false
|
9
|
-
@lists = QPush.keys.perform_lists
|
10
9
|
end
|
11
10
|
|
12
11
|
# Starts our perform process. This will run until instructed to stop.
|
@@ -29,7 +28,7 @@ module QPush
|
|
29
28
|
# Performs a 'blocking pop' on our redis job list.
|
30
29
|
#
|
31
30
|
def retrieve_job
|
32
|
-
json =
|
31
|
+
json = Server.redis { |c| c.brpop(Server.keys.perform_list) }
|
33
32
|
Job.new(JSON.parse(json.last))
|
34
33
|
rescue => e
|
35
34
|
raise ServerError, e.message
|
data/lib/qpush/server/queue.rb
CHANGED
@@ -29,7 +29,7 @@ module QPush
|
|
29
29
|
# Performs a 'blocking pop' on our redis job list.
|
30
30
|
#
|
31
31
|
def retrieve_job
|
32
|
-
json =
|
32
|
+
json = Server.redis { |c| c.brpop(Server.keys.queue) }
|
33
33
|
Job.new(JSON.parse(json.last))
|
34
34
|
rescue => e
|
35
35
|
raise ServerError, e.message
|