litejob 0.1.0 → 0.2.0
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/.standard.yml +4 -1
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +20 -1
- data/README.md +5 -0
- data/Rakefile +28 -0
- data/lib/litejob/client.rb +44 -0
- data/lib/litejob/processor.rb +41 -0
- data/lib/litejob/server.rb +67 -0
- data/lib/litejob/version.rb +1 -1
- data/lib/litejob.rb +46 -2
- metadata +48 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78cf5ea54febd08b520ed3d25c27ebbf3e83ec04653a52a351db0366dbf7d4bb
|
4
|
+
data.tar.gz: 8bfcfd530be21fc277140f160568df112173d88b85bd89fbb7d6ef26d612599f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84dc5fbc75d0ec788d6c2a2268cbf01232b7a4ca4ff01d2600348a25c2d2129ecae7d08d0bdf489039409cfa19a786da49981ac6ee21f2bc6407ddf427a5d688
|
7
|
+
data.tar.gz: 03c820e84b226b479b9d2f5180541c788f691c11ecd32b78b304cb6b49293f85f19d02287818907bfe8385bc5ed5c5d30b5e2b34799d65b7e710d692bfdda653
|
data/.standard.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,24 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
litejob (0.
|
4
|
+
litejob (0.2.0)
|
5
|
+
litequeue (>= 0.2.0)
|
6
|
+
litescheduler (>= 0.2.1)
|
5
7
|
|
6
8
|
GEM
|
7
9
|
remote: https://rubygems.org/
|
8
10
|
specs:
|
9
11
|
ast (2.4.2)
|
12
|
+
docile (1.4.0)
|
10
13
|
json (2.6.3)
|
11
14
|
language_server-protocol (3.17.0.3)
|
12
15
|
lint_roller (1.1.0)
|
16
|
+
litedb (0.2.1)
|
17
|
+
litescheduler (>= 0.2.0)
|
18
|
+
sqlite3 (>= 1.5.0)
|
19
|
+
litequeue (0.2.0)
|
20
|
+
litedb (>= 0.2.1)
|
21
|
+
litescheduler (0.2.1)
|
13
22
|
minitest (5.19.0)
|
14
23
|
parallel (1.23.0)
|
15
24
|
parser (3.2.2.3)
|
@@ -36,6 +45,14 @@ GEM
|
|
36
45
|
rubocop (>= 1.7.0, < 2.0)
|
37
46
|
rubocop-ast (>= 0.4.0)
|
38
47
|
ruby-progressbar (1.13.0)
|
48
|
+
simplecov (0.22.0)
|
49
|
+
docile (~> 1.1)
|
50
|
+
simplecov-html (~> 0.11)
|
51
|
+
simplecov_json_formatter (~> 0.1)
|
52
|
+
simplecov-html (0.12.3)
|
53
|
+
simplecov_json_formatter (0.1.4)
|
54
|
+
sqlite3 (1.6.3-arm64-darwin)
|
55
|
+
sqlite3 (1.6.3-x86_64-linux)
|
39
56
|
standard (1.30.1)
|
40
57
|
language_server-protocol (~> 3.17.0.2)
|
41
58
|
lint_roller (~> 1.0)
|
@@ -52,11 +69,13 @@ GEM
|
|
52
69
|
|
53
70
|
PLATFORMS
|
54
71
|
arm64-darwin-21
|
72
|
+
x86_64-linux
|
55
73
|
|
56
74
|
DEPENDENCIES
|
57
75
|
litejob!
|
58
76
|
minitest (~> 5.0)
|
59
77
|
rake (~> 13.0)
|
78
|
+
simplecov
|
60
79
|
standard (~> 1.3)
|
61
80
|
|
62
81
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Litejob
|
2
2
|
|
3
|
+
[](https://rubygems.org/gems/litejob)
|
4
|
+
[](https://rubygems.org/gems/litejob)
|
5
|
+

|
6
|
+

|
7
|
+
|
3
8
|
TODO: Delete this and the text below, and describe your gem
|
4
9
|
|
5
10
|
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/litejob`. To experiment with that code, run `bin/console` for an interactive prompt.
|
data/Rakefile
CHANGED
@@ -9,6 +9,34 @@ Rake::TestTask.new(:test) do |t|
|
|
9
9
|
t.test_files = FileList["test/**/test_*.rb"]
|
10
10
|
end
|
11
11
|
|
12
|
+
desc "Update the README code coverage badge"
|
13
|
+
task :update_readme_coverage_badge do
|
14
|
+
require "json"
|
15
|
+
|
16
|
+
next unless File.exist?("coverage/.last_run.json")
|
17
|
+
|
18
|
+
last_run_coverage = JSON.load_file("coverage/.last_run.json")
|
19
|
+
line_coverage = last_run_coverage.dig("result", "line")
|
20
|
+
branch_coverage = last_run_coverage.dig("result", "branch")
|
21
|
+
average_coverage = [(branch_coverage * 1), (line_coverage * 1.5)].sum.fdiv(2.5).round
|
22
|
+
badge_color = if average_coverage >= 75
|
23
|
+
:brightgreen
|
24
|
+
else
|
25
|
+
:red
|
26
|
+
end
|
27
|
+
|
28
|
+
coverage_badge_re = /!\[Coverage\]\(https:\/\/img.shields.io\/badge\/code_coverage-(.*?)\)/
|
29
|
+
last_run_coverage_badge = ""
|
30
|
+
|
31
|
+
new_readme = File.read("README.md").gsub(coverage_badge_re, last_run_coverage_badge)
|
32
|
+
|
33
|
+
File.write("README.md", new_readme)
|
34
|
+
|
35
|
+
puts "Updated README code coverage badge to show #{average_coverage}% coverage."
|
36
|
+
end
|
37
|
+
|
38
|
+
task cov: %i[test update_readme_coverage_badge]
|
39
|
+
|
12
40
|
require "standard/rake"
|
13
41
|
|
14
42
|
task default: %i[test standard]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "litequeue"
|
5
|
+
|
6
|
+
module Litejob
|
7
|
+
# Litejob::Client is responsible for pushing job payloads to the SQLite queue.
|
8
|
+
class Client
|
9
|
+
def initialize
|
10
|
+
@queue = Litequeue.instance
|
11
|
+
end
|
12
|
+
|
13
|
+
def push(jobclass, params, options = {})
|
14
|
+
delay = options[:delay] || 0
|
15
|
+
attempts = options[:attempts] || 5
|
16
|
+
queue = options[:queue]
|
17
|
+
payload = JSON.dump({class: jobclass, params: params, attempts: attempts, queue: queue})
|
18
|
+
atomic_push(payload, delay, queue)
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete(id)
|
22
|
+
payload = @queue.delete(id)
|
23
|
+
JSON.parse(payload)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def atomic_push(payload, delay, queue)
|
29
|
+
retryable = true
|
30
|
+
begin
|
31
|
+
@queue.push(payload, queue: queue, delay: delay)
|
32
|
+
rescue => exception
|
33
|
+
# Retry once retryable exceptions
|
34
|
+
# https://github.com/sparklemotion/sqlite3-ruby/blob/master/lib/sqlite3/errors.rb
|
35
|
+
if retryable && exception.is_a?(SQLite3::BusyException)
|
36
|
+
retryable = false
|
37
|
+
retry
|
38
|
+
else
|
39
|
+
raise exception
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "litequeue"
|
5
|
+
|
6
|
+
module Litejob
|
7
|
+
# Litejob::Processor is responsible for processing job payloads
|
8
|
+
class Processor
|
9
|
+
def initialize(payload)
|
10
|
+
@payload = payload
|
11
|
+
@queue = Litequeue.instance
|
12
|
+
end
|
13
|
+
|
14
|
+
def repush(id, job, delay = 0, queue = nil)
|
15
|
+
@queue.repush(id, JSON.dump(job), queue: queue, delay: delay)
|
16
|
+
end
|
17
|
+
|
18
|
+
def process!
|
19
|
+
id, serialized_job = @payload
|
20
|
+
job_hash = JSON.parse(serialized_job)
|
21
|
+
klass = Object.const_get(job_hash["class"])
|
22
|
+
instance = klass.new
|
23
|
+
|
24
|
+
begin
|
25
|
+
instance.perform(*job_hash["params"])
|
26
|
+
rescue
|
27
|
+
if job_hash["retries_left"] == 0
|
28
|
+
repush(id, job_hash, 0, "_dead")
|
29
|
+
else
|
30
|
+
job_hash["retries_left"] ||= job_hash["attempts"]
|
31
|
+
job_hash["retries_left"] -= 1
|
32
|
+
retry_delay = (job_hash["attempts"] - job_hash["retries_left"]) * 0.1
|
33
|
+
repush(id, job_hash, retry_delay, job_hash["queue"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue => exception # standard:disable Lint/UselessRescue
|
37
|
+
# this is an error in the extraction of job info, retrying here will not be useful
|
38
|
+
raise exception
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "litequeue"
|
4
|
+
require "litescheduler"
|
5
|
+
|
6
|
+
module Litejob
|
7
|
+
# Litejob::Server is responsible for popping job payloads from the SQLite queue.
|
8
|
+
# :nocov:
|
9
|
+
class Server
|
10
|
+
def initialize(queues)
|
11
|
+
@queue = Litequeue.instance
|
12
|
+
@scheduler = Litescheduler.instance
|
13
|
+
@queues = queues
|
14
|
+
# group and order queues according to their priority
|
15
|
+
@prioritized_queues = queues.each_with_object({}) do |(name, priority, spawns), memo|
|
16
|
+
memo[priority] ||= []
|
17
|
+
memo[priority] << [name, spawns == "spawn"]
|
18
|
+
end.sort_by do |priority, _|
|
19
|
+
-priority
|
20
|
+
end
|
21
|
+
@running = true
|
22
|
+
@sleep_intervals = [0.001, 0.005, 0.025, 0.125, 0.625, 1.0, 2.0]
|
23
|
+
run!
|
24
|
+
end
|
25
|
+
|
26
|
+
def pop(queue)
|
27
|
+
result = @queue.pop(queue: queue)
|
28
|
+
|
29
|
+
return result[0] if result.length == 1
|
30
|
+
return false if result.empty?
|
31
|
+
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def run!
|
36
|
+
@scheduler.spawn do
|
37
|
+
worker_sleep_index = 0
|
38
|
+
while @running
|
39
|
+
processed = 0
|
40
|
+
@prioritized_queues.each do |priority, queues|
|
41
|
+
queues.each do |queue, spawns|
|
42
|
+
batched = 0
|
43
|
+
while (batched < priority) && (payload = pop(queue))
|
44
|
+
batched += 1
|
45
|
+
processed += 1
|
46
|
+
|
47
|
+
processor = Processor.new(payload)
|
48
|
+
processor.process!
|
49
|
+
|
50
|
+
# give other contexts a chance to run here
|
51
|
+
@scheduler.switch
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if processed == 0
|
56
|
+
sleep @sleep_intervals[worker_sleep_index]
|
57
|
+
worker_sleep_index += 1 if worker_sleep_index < @sleep_intervals.length - 1
|
58
|
+
else
|
59
|
+
worker_sleep_index = 0 # reset the index
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
# :nocov:
|
67
|
+
end
|
data/lib/litejob/version.rb
CHANGED
data/lib/litejob.rb
CHANGED
@@ -1,8 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "litejob/version"
|
4
|
+
require_relative "litejob/client"
|
4
5
|
|
6
|
+
# Litejob is responsible for providing an interface to job classes
|
5
7
|
module Litejob
|
6
|
-
|
7
|
-
|
8
|
+
def self.included(klass)
|
9
|
+
klass.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def perform_async(*params)
|
14
|
+
@litejob_options ||= {}
|
15
|
+
client.push(name, params, @litejob_options.merge(delay: 0, queue: queue_name))
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform_at(time, *params)
|
19
|
+
@litejob_options ||= {}
|
20
|
+
delay = time.to_i - Time.now.to_i
|
21
|
+
client.push(name, params, @litejob_options.merge(delay: delay, queue: queue_name))
|
22
|
+
end
|
23
|
+
|
24
|
+
def perform_in(delay, *params)
|
25
|
+
@litejob_options ||= {}
|
26
|
+
client.push(name, params, @litejob_options.merge(delay: delay, queue: queue_name))
|
27
|
+
end
|
28
|
+
alias_method :perform_after, :perform_in
|
29
|
+
|
30
|
+
def delete(id)
|
31
|
+
client.delete(id)
|
32
|
+
end
|
33
|
+
|
34
|
+
def queue_as(queue_name)
|
35
|
+
@queue_name = queue_name.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def litejob_options(options)
|
39
|
+
@litejob_options = options
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def queue_name
|
45
|
+
@queue_name || "default"
|
46
|
+
end
|
47
|
+
|
48
|
+
def client
|
49
|
+
@client ||= Client.new
|
50
|
+
end
|
51
|
+
end
|
8
52
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: litejob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mohamed Hassan
|
@@ -9,8 +9,50 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-08-
|
13
|
-
dependencies:
|
12
|
+
date: 2023-08-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: litescheduler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.2.1
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.2.1
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: litequeue
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.2.0
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.2.0
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: simplecov
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
14
56
|
description:
|
15
57
|
email:
|
16
58
|
- oldmoe@gmail.com
|
@@ -28,6 +70,9 @@ files:
|
|
28
70
|
- README.md
|
29
71
|
- Rakefile
|
30
72
|
- lib/litejob.rb
|
73
|
+
- lib/litejob/client.rb
|
74
|
+
- lib/litejob/processor.rb
|
75
|
+
- lib/litejob/server.rb
|
31
76
|
- lib/litejob/version.rb
|
32
77
|
- sig/litejob.rbs
|
33
78
|
homepage: https://github.com/litestack-ruby/litejob
|