belated 0.3.1 → 0.4.1
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/.gitignore +3 -1
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +17 -1
- data/README.md +22 -9
- data/lib/belated.rb +34 -27
- data/lib/belated/client.rb +15 -2
- data/lib/belated/job.rb +1 -0
- data/lib/belated/queue.rb +79 -0
- data/lib/belated/version.rb +1 -1
- data/lib/belated/worker.rb +8 -5
- metadata +4 -3
- data/hard_worker_dump +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed06672798a42b07c69c9dc84f32d1ba12a58a7b95028f0c4a2f5d1a5f0b04c4
|
4
|
+
data.tar.gz: 0ecf13b8abf076c5fbe8a0037017840e55f32c674f4a40092a6e35845503f4e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e16e639db3c05d9112a4b31232d0cb78dbe6fe93ed05cd33f1d9a7856ded7c40319c145c20cddf1dd5a8bafb2894d8f96d46fc423a6718180e4d5e4584fdc41
|
7
|
+
data.tar.gz: 86793a533285a0ae5761b3eb11d4f16fe44793cc83d2a24c6f7aebae6a4d27ff7795b3ef2e69ce7e2b12f5c86fb9e108d5252f2aa863c645262f880f0ad56cf7
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.4.1] - 2021-08-05
|
3
4
|
|
5
|
+
- Now handles saving future jobs too! So if you have a job enqueued for tomorrow, and restart Belated, it should still be enqueued.
|
6
|
+
|
7
|
+
## [0.4.0] - 2021-08-03
|
8
|
+
|
9
|
+
- Now you can enqueue jobs to be done at a later time. Just pass an `at:` keyword param to the client.
|
10
|
+
- Does not save the jobs when you quit.
|
11
|
+
|
12
|
+
## [0.3.3] - 2021-08-01
|
13
|
+
|
14
|
+
- Shutdown trapped signal thread, make sure :shutdown is not recorded as a job.
|
15
|
+
|
16
|
+
## [0.3.2] - 2021-07-31
|
17
|
+
|
18
|
+
- Trap INT and TERM, so now the shutdown is a little bit more graceful.
|
4
19
|
|
5
20
|
## [0.3.1] - 2021-07-29
|
6
21
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
belated (0.
|
4
|
+
belated (0.4.1)
|
5
5
|
drb
|
6
6
|
dry-configurable
|
7
7
|
|
@@ -72,6 +72,10 @@ GEM
|
|
72
72
|
byebug (11.1.3)
|
73
73
|
concurrent-ruby (1.1.9)
|
74
74
|
crass (1.0.6)
|
75
|
+
database_cleaner-active_record (2.0.1)
|
76
|
+
activerecord (>= 5.a)
|
77
|
+
database_cleaner-core (~> 2.0.0)
|
78
|
+
database_cleaner-core (2.0.1)
|
75
79
|
diff-lcs (1.4.4)
|
76
80
|
drb (2.0.4)
|
77
81
|
dry-configurable (0.12.1)
|
@@ -145,6 +149,14 @@ GEM
|
|
145
149
|
rspec-mocks (3.10.2)
|
146
150
|
diff-lcs (>= 1.2.0, < 2.0)
|
147
151
|
rspec-support (~> 3.10.0)
|
152
|
+
rspec-rails (5.0.1)
|
153
|
+
actionpack (>= 5.2)
|
154
|
+
activesupport (>= 5.2)
|
155
|
+
railties (>= 5.2)
|
156
|
+
rspec-core (~> 3.10)
|
157
|
+
rspec-expectations (~> 3.10)
|
158
|
+
rspec-mocks (~> 3.10)
|
159
|
+
rspec-support (~> 3.10)
|
148
160
|
rspec-support (3.10.2)
|
149
161
|
rubocop (1.18.3)
|
150
162
|
parallel (~> 1.10)
|
@@ -166,6 +178,7 @@ GEM
|
|
166
178
|
activesupport (>= 4.0)
|
167
179
|
sprockets (>= 3.0.0)
|
168
180
|
sqlite3 (1.4.2)
|
181
|
+
stackprof (0.2.16)
|
169
182
|
thor (1.1.0)
|
170
183
|
tzinfo (2.0.4)
|
171
184
|
concurrent-ruby (~> 1.0)
|
@@ -181,11 +194,14 @@ PLATFORMS
|
|
181
194
|
DEPENDENCIES
|
182
195
|
belated!
|
183
196
|
byebug
|
197
|
+
database_cleaner-active_record
|
184
198
|
rails (>= 6.1.3)
|
185
199
|
rake (~> 13.0)
|
186
200
|
rspec (~> 3.0)
|
201
|
+
rspec-rails
|
187
202
|
rubocop (~> 1.7)
|
188
203
|
sqlite3
|
204
|
+
stackprof
|
189
205
|
|
190
206
|
BUNDLED WITH
|
191
207
|
2.2.17
|
data/README.md
CHANGED
@@ -8,21 +8,28 @@ Note that Belated used to be called HardWorker. That name was already in use in
|
|
8
8
|
|
9
9
|
It uses dRuby to do the communication! Which is absolute great. No need for Redis or PostgreSQL, just Ruby standard libraries.
|
10
10
|
|
11
|
+
Can be used with or without Rails.
|
12
|
+
|
11
13
|
TODO LIST:
|
12
14
|
|
13
|
-
- ~~Marshal the job queue into a file so you don't lose all progress~~
|
14
|
-
(Ended up using YAML)
|
15
15
|
- Catch SIGTERM and friends
|
16
|
-
-
|
17
|
-
- ~~Parse options from command line, eg. `--workers 10`~~(Done!)
|
16
|
+
- Now supports it, partly.
|
18
17
|
- Don't crash on errors (Partially done)
|
19
|
-
-
|
20
|
-
- Make it possible to schedule jobs
|
18
|
+
- Have multiple queues?
|
21
19
|
- Maybe support ActiveJob?
|
22
20
|
- Have a web UI
|
23
21
|
- Do some performance testing
|
24
22
|
- Add a section telling people to use Sidekiq if they can
|
25
23
|
|
24
|
+
DONE
|
25
|
+
|
26
|
+
- ~~Make it possible to schedule jobs~~
|
27
|
+
- ~~Marshal the job queue into a file so you don't lose all progress~~
|
28
|
+
(Ended up using YAML)
|
29
|
+
- ~~Add a logger~~
|
30
|
+
- ~~Support Rails~~ (Supported!)
|
31
|
+
- ~~Parse options from command line, eg. `--workers 10`~~(Done!)
|
32
|
+
|
26
33
|
## Installation
|
27
34
|
|
28
35
|
Add this line to your application's Gemfile:
|
@@ -94,6 +101,12 @@ client.perform_belated(job)
|
|
94
101
|
|
95
102
|
If you want to pass a job to Belated.
|
96
103
|
|
104
|
+
If you don't want the job to run right away, you can also pass it a keyword param `at:` like so:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
client.perform_belated(job, Time.now + 1.month)
|
108
|
+
```
|
109
|
+
|
97
110
|
# Settings
|
98
111
|
|
99
112
|
Configuring Belated:
|
@@ -109,15 +122,15 @@ end
|
|
109
122
|
|
110
123
|
From command line:
|
111
124
|
|
112
|
-
$ bundle exec belated --rails=true
|
125
|
+
$ bundle exec belated --rails=true
|
113
126
|
|
114
127
|
Use Rails or not.
|
115
128
|
|
116
|
-
$ bundle exec belated --rails_path=/my_rails_project
|
129
|
+
$ bundle exec belated --rails_path=/my_rails_project
|
117
130
|
|
118
131
|
Path to Rails project.
|
119
132
|
|
120
|
-
$ bundle exec belated --workers=10
|
133
|
+
$ bundle exec belated --workers=10
|
121
134
|
|
122
135
|
Number of workers.
|
123
136
|
|
data/lib/belated.rb
CHANGED
@@ -9,6 +9,7 @@ require 'singleton'
|
|
9
9
|
require 'dry-configurable'
|
10
10
|
require 'belated/client'
|
11
11
|
require 'logger'
|
12
|
+
require 'belated/queue'
|
12
13
|
|
13
14
|
# Belated is a pure Ruby job backend.
|
14
15
|
# It has limited functionality, as it only accepts
|
@@ -21,8 +22,7 @@ class Belated
|
|
21
22
|
include Logging
|
22
23
|
include Singleton unless $TESTING
|
23
24
|
URI = 'druby://localhost:8788'
|
24
|
-
|
25
|
-
@@queue = Queue.new
|
25
|
+
@@queue = Belated::Queue.new
|
26
26
|
|
27
27
|
setting :rails, true
|
28
28
|
setting :rails_path, '.'
|
@@ -36,17 +36,17 @@ class Belated
|
|
36
36
|
# Aliased for testing purposes.
|
37
37
|
# This is only run from the bin file.
|
38
38
|
def start
|
39
|
-
boot_app
|
40
|
-
load_jobs
|
39
|
+
boot_app && @@queue.load_jobs
|
41
40
|
@worker_list = []
|
42
|
-
Belated.config.workers.times do |
|
43
|
-
@worker_list << Thread.new { Worker.new }
|
41
|
+
Belated.config.workers.times do |i|
|
42
|
+
@worker_list << Thread.new { Worker.new(number: i.next) }
|
44
43
|
end
|
45
44
|
return unless Belated.config.connect
|
46
45
|
|
47
46
|
connect!
|
48
47
|
banner_and_info
|
49
|
-
|
48
|
+
trap_signals
|
49
|
+
enqueue_future_jobs
|
50
50
|
end
|
51
51
|
alias initialize start
|
52
52
|
|
@@ -55,10 +55,19 @@ class Belated
|
|
55
55
|
DRb.start_service(URI, @@queue, verbose: true)
|
56
56
|
rescue DRb::DRbConnError, Errno::EADDRINUSE
|
57
57
|
Belated.logger.error 'Could not connect to DRb server.'
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
end
|
59
|
+
|
60
|
+
def trap_signals
|
61
|
+
%w[INT TERM].each do |signal|
|
62
|
+
Signal.trap(signal) do
|
63
|
+
@worker_list.length.times do
|
64
|
+
@@queue.push(:shutdown)
|
65
|
+
end
|
66
|
+
Thread.new { stop_workers }
|
67
|
+
sleep 0.1 until @@queue.empty? || $TESTING
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
end
|
62
71
|
end
|
63
72
|
|
64
73
|
def boot_app
|
@@ -74,33 +83,31 @@ class Belated
|
|
74
83
|
Belated.config.rails
|
75
84
|
end
|
76
85
|
|
77
|
-
def
|
78
|
-
log
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
86
|
+
def enqueue_future_jobs
|
87
|
+
log 'starting future jobs thread'
|
88
|
+
loop do
|
89
|
+
@@queue.future_jobs.each_with_index do |job, i|
|
90
|
+
if job[:at] <= Time.now.utc
|
91
|
+
log @@queue.future_jobs.delete_at(i)
|
92
|
+
@@queue.push(job[:klass])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
sleep 0.01
|
84
96
|
end
|
85
|
-
File.delete(Belated::FILE_NAME)
|
86
97
|
end
|
87
98
|
|
88
99
|
def reload
|
89
100
|
log 'reloading...'
|
90
|
-
load_jobs
|
101
|
+
@@queue.load_jobs
|
91
102
|
end
|
92
103
|
|
93
104
|
def stop_workers
|
94
105
|
@worker_list&.each do |worker|
|
106
|
+
sleep 0.1 if worker.alive?
|
95
107
|
Thread.kill(worker)
|
96
108
|
end
|
97
|
-
|
98
|
-
|
99
|
-
next if (klass = @@queue.pop).instance_of?(Proc)
|
100
|
-
|
101
|
-
class_array << klass
|
102
|
-
end
|
103
|
-
pp File.open(FILE_NAME, 'wb') { |f| f.write(YAML.dump(class_array)) }
|
109
|
+
@@queue.save_jobs
|
110
|
+
exit unless $TESTING
|
104
111
|
end
|
105
112
|
|
106
113
|
def banner
|
data/lib/belated/client.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
class Belated
|
2
|
+
# The client class is responsible for managing the connection to the
|
3
|
+
# DRb server.
|
4
|
+
# You can enqueue jobs to be processed by the server.
|
5
|
+
# Example:
|
6
|
+
# client = Belated::Client.new
|
7
|
+
# client.enqueue(JubJub.new, at: Time.now + 5.seconds)
|
2
8
|
class Client
|
3
9
|
attr_accessor :queue
|
4
10
|
|
11
|
+
# Starts up the client.
|
12
|
+
# Connects to the queue through DRb.
|
13
|
+
# @return [void]
|
5
14
|
def initialize
|
6
15
|
server_uri = Belated::URI
|
7
16
|
# @bank =
|
@@ -9,8 +18,12 @@ class Belated
|
|
9
18
|
self.queue = DRbObject.new_with_uri(server_uri)
|
10
19
|
end
|
11
20
|
|
12
|
-
|
13
|
-
|
21
|
+
# The method that pushes the jobs to the queue.
|
22
|
+
# @param job [Object] - The the job to be pushed.
|
23
|
+
# @param at [Date] - The time at which the job should be executed.
|
24
|
+
# @return [Object] - The job that was pushed.
|
25
|
+
def perform(job, at: nil)
|
26
|
+
queue.push(job, at: at)
|
14
27
|
end
|
15
28
|
alias perform_belated perform
|
16
29
|
alias perform_later perform
|
data/lib/belated/job.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Job = Struct.new(:klass, :at)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'belated/job'
|
4
|
+
require 'belated/logging'
|
5
|
+
class Belated
|
6
|
+
class Queue
|
7
|
+
include Logging
|
8
|
+
attr_accessor :future_jobs
|
9
|
+
|
10
|
+
FILE_NAME = 'belated_dump'
|
11
|
+
|
12
|
+
def initialize(queue: Thread::Queue.new, future_jobs: [])
|
13
|
+
@queue = queue
|
14
|
+
self.future_jobs = future_jobs
|
15
|
+
end
|
16
|
+
|
17
|
+
def push(job, at: nil)
|
18
|
+
if at.nil?
|
19
|
+
@queue.push(job)
|
20
|
+
else
|
21
|
+
@future_jobs << Job.new(job, at)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop
|
26
|
+
@queue.pop
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear
|
30
|
+
@queue.clear
|
31
|
+
self.future_jobs = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def empty?
|
35
|
+
@queue.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def length
|
39
|
+
@queue.length
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_jobs
|
43
|
+
log "reloading... if file exists #{File.exist?(FILE_NAME)}"
|
44
|
+
return unless File.exist?(FILE_NAME)
|
45
|
+
|
46
|
+
jobs = YAML.load(File.binread(FILE_NAME))
|
47
|
+
jobs.each do |job|
|
48
|
+
if job.is_a?(Job)
|
49
|
+
future_jobs.push(job)
|
50
|
+
else
|
51
|
+
@queue.push(job)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
File.delete(FILE_NAME)
|
55
|
+
end
|
56
|
+
|
57
|
+
def save_jobs
|
58
|
+
class_array = []
|
59
|
+
@queue.length.times do |_i|
|
60
|
+
unless proc_or_shutdown?(klass = @queue.pop)
|
61
|
+
class_array << klass
|
62
|
+
end
|
63
|
+
end
|
64
|
+
future_jobs.each do |_job|
|
65
|
+
unless proc_or_shutdown?(klass = future_jobs.pop)
|
66
|
+
class_array << klass
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
pp File.open(FILE_NAME, 'wb') { |f| f.write(YAML.dump(class_array)) }
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def proc_or_shutdown?(job)
|
76
|
+
job.instance_of?(Proc) || job == :shutdown
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/belated/version.rb
CHANGED
data/lib/belated/worker.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
require_relative 'logging'
|
2
2
|
class Belated
|
3
3
|
# The worker class that actually gets the jobs from the queue
|
4
|
-
# and calls them. Expects the jobs to be procs
|
4
|
+
# and calls them. Expects the jobs to be procs or
|
5
|
+
# classes that have a perform method.
|
5
6
|
class Worker
|
6
7
|
include Logging
|
7
8
|
|
8
|
-
def initialize
|
9
|
+
def initialize(number: 1)
|
10
|
+
@number = number
|
9
11
|
start_working
|
10
12
|
end
|
11
13
|
|
12
14
|
def start_working
|
13
15
|
loop do
|
14
|
-
|
15
|
-
next unless job
|
16
|
+
log "Worker #{@number} fetching jobs!"
|
17
|
+
next unless (job = Belated.fetch_job)
|
18
|
+
|
19
|
+
break if job == :shutdown
|
16
20
|
|
17
21
|
log call_job(job)
|
18
|
-
log 'fetching jobs...'
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: belated
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sampo Kuokkanen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: drb
|
@@ -78,10 +78,11 @@ files:
|
|
78
78
|
- bin/bundle
|
79
79
|
- bin/console
|
80
80
|
- bin/setup
|
81
|
-
- hard_worker_dump
|
82
81
|
- lib/belated.rb
|
83
82
|
- lib/belated/client.rb
|
83
|
+
- lib/belated/job.rb
|
84
84
|
- lib/belated/logging.rb
|
85
|
+
- lib/belated/queue.rb
|
85
86
|
- lib/belated/rails.rb
|
86
87
|
- lib/belated/version.rb
|
87
88
|
- lib/belated/worker.rb
|
data/hard_worker_dump
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--- []
|