async-job 0.2.1 → 0.4.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
- checksums.yaml.gz.sig +0 -0
- data/lib/async/job/backend/inline/server.rb +32 -0
- data/lib/async/job/backend/inline.rb +18 -0
- data/lib/async/job/backend/redis/server.rb +23 -16
- data/lib/async/job/backend/redis.rb +2 -6
- data/lib/async/job/buffer.rb +28 -0
- data/lib/async/job/builder.rb +70 -0
- data/lib/async/job/coder/json.rb +27 -0
- data/lib/async/job/coder/marshal.rb +24 -0
- data/lib/async/job/coder/message_pack.rb +35 -0
- data/lib/async/job/coder.rb +31 -0
- data/lib/async/job/generic.rb +3 -3
- data/lib/async/job/version.rb +1 -1
- data/lib/async/job.rb +1 -0
- data/readme.md +5 -1
- data.tar.gz.sig +0 -0
- metadata +11 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e330cf8c0430796e25264e8c892f70423f1fa0ffbc645a19198774f51ef4893
|
4
|
+
data.tar.gz: 3c1ac69a6bde193876717c65dace5e97803b66ab9471d5baeffc33bb1762701a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 956e76aadce5f21fd099ba72d38914f4a4a6981a1d4382eee34a7bc37a0d79cb7bedb6b93000146a752fdc829945a93c72ef873fc3012acda5f6ea50d58128ae
|
7
|
+
data.tar.gz: 8fb1c37bc2f065c08a08dbdc25f04dbfe2aab5d67eb57c297a50fb5665e9840014fe1c3bd7257fc2dfa463919507fdf450dcaa71d1c17dc5cde0441b949c108b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative '../../coder'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
module Backend
|
11
|
+
module Inline
|
12
|
+
class Server
|
13
|
+
def initialize(delegate)
|
14
|
+
@delegate = delegate
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(job)
|
18
|
+
scheduled_at = Coder::Time(job["scheduled_at"])
|
19
|
+
|
20
|
+
Async do
|
21
|
+
if scheduled_at
|
22
|
+
sleep(scheduled_at - Time.now)
|
23
|
+
end
|
24
|
+
|
25
|
+
@delegate.call(job)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'inline/server'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
module Backend
|
11
|
+
module Inline
|
12
|
+
def self.new(delegate)
|
13
|
+
return Server.new(delegate)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -9,16 +9,21 @@ require_relative 'processing_queue'
|
|
9
9
|
require_relative 'ready_queue'
|
10
10
|
|
11
11
|
require 'securerandom'
|
12
|
+
require_relative '../../coder'
|
12
13
|
|
13
14
|
module Async
|
14
15
|
module Job
|
15
16
|
module Backend
|
16
17
|
module Redis
|
17
18
|
class Server
|
18
|
-
def initialize(client, prefix)
|
19
|
+
def initialize(delegate, client, prefix: 'async-job', coder: Coder::DEFAULT, resolution: 10)
|
20
|
+
@delegate = delegate
|
21
|
+
|
19
22
|
@id = SecureRandom.uuid
|
20
23
|
@client = client
|
21
24
|
@prefix = prefix
|
25
|
+
@coder = coder
|
26
|
+
@resolution = resolution
|
22
27
|
|
23
28
|
@job_store = JobStore.new(@client, "#{@prefix}:jobs")
|
24
29
|
|
@@ -31,37 +36,39 @@ module Async
|
|
31
36
|
def start
|
32
37
|
Console.info(self, "Starting server...")
|
33
38
|
# Start the delayed queue, which will move jobs to the ready queue when they are ready:
|
34
|
-
@delayed_queue.start(@ready_queue)
|
39
|
+
@delayed_queue.start(@ready_queue, resolution: @resolution)
|
35
40
|
|
36
41
|
# Start the processing queue, which will move jobs to the ready queue when they are abandoned:
|
37
42
|
@processing_queue.start
|
43
|
+
|
44
|
+
while true
|
45
|
+
self.dequeue
|
46
|
+
end
|
38
47
|
end
|
39
48
|
|
40
|
-
def
|
41
|
-
|
49
|
+
def call(job)
|
50
|
+
scheduled_at = Coder::Time(job["scheduled_at"])
|
51
|
+
|
52
|
+
if scheduled_at
|
53
|
+
@delayed_queue.add(@coder.dump(job), scheduled_at, @job_store)
|
54
|
+
else
|
55
|
+
@ready_queue.add(@coder.dump(job), @job_store)
|
56
|
+
end
|
42
57
|
end
|
43
58
|
|
44
|
-
|
45
|
-
@delayed_queue.add(job, timestamp, @job_store)
|
46
|
-
end
|
59
|
+
protected
|
47
60
|
|
48
|
-
def
|
61
|
+
def dequeue
|
49
62
|
id = @processing_queue.fetch
|
50
63
|
begin
|
51
|
-
job = @job_store.get(id)
|
52
|
-
|
64
|
+
job = @coder.load(@job_store.get(id))
|
65
|
+
@delegate.call(job)
|
53
66
|
@processing_queue.complete(id)
|
54
67
|
rescue => error
|
55
68
|
@processing_queue.retry(id)
|
56
69
|
raise
|
57
70
|
end
|
58
71
|
end
|
59
|
-
|
60
|
-
def each(&block)
|
61
|
-
while true
|
62
|
-
process(&block)
|
63
|
-
end
|
64
|
-
end
|
65
72
|
end
|
66
73
|
end
|
67
74
|
end
|
@@ -10,13 +10,9 @@ module Async
|
|
10
10
|
module Job
|
11
11
|
module Backend
|
12
12
|
module Redis
|
13
|
-
def self.new(**options)
|
14
|
-
endpoint = options.fetch(:endpoint) {Async::Redis.local_endpoint}
|
15
|
-
prefix = options.fetch(:prefix) {"async:job"}
|
16
|
-
|
13
|
+
def self.new(delegate, endpoint: Async::Redis.local_endpoint, **options)
|
17
14
|
client = Async::Redis::Client.new(endpoint)
|
18
|
-
|
19
|
-
return Async::Job::Backend::Redis::Server.new(client, prefix)
|
15
|
+
return Server.new(delegate, client, **options)
|
20
16
|
end
|
21
17
|
end
|
22
18
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'async/queue'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
class Buffer
|
11
|
+
def initialize(delegate = nil)
|
12
|
+
@jobs = Async::Queue.new
|
13
|
+
@delegate = delegate
|
14
|
+
end
|
15
|
+
|
16
|
+
attr :jobs
|
17
|
+
|
18
|
+
def call(job)
|
19
|
+
@jobs.enqueue(job)
|
20
|
+
@delegate&.call(job)
|
21
|
+
end
|
22
|
+
|
23
|
+
def pop
|
24
|
+
@jobs.dequeue
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
module Job
|
8
|
+
class Builder
|
9
|
+
Pipeline = Struct.new(:producer, :consumer, :delegate)
|
10
|
+
|
11
|
+
def self.build(delegate = nil, &block)
|
12
|
+
builder = self.new(delegate)
|
13
|
+
|
14
|
+
builder.instance_eval(&block)
|
15
|
+
|
16
|
+
return builder.build
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(delegate = nil)
|
20
|
+
@enqueue = []
|
21
|
+
@dequeue = []
|
22
|
+
@delegate = delegate
|
23
|
+
|
24
|
+
@queue = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def enqueue(middleware)
|
28
|
+
@enqueue << middleware
|
29
|
+
end
|
30
|
+
|
31
|
+
def queue(queue, *arguments, **options)
|
32
|
+
# The delegate is the output side of the queue, e.g. a Queuedelegate or similar wrapper.
|
33
|
+
# The queue itself is instantiated with the delegate.
|
34
|
+
@queue = ->(delegate){queue.new(delegate, *arguments, **options)}
|
35
|
+
end
|
36
|
+
|
37
|
+
def dequeue(middleware)
|
38
|
+
@dequeue << middleware
|
39
|
+
end
|
40
|
+
|
41
|
+
def delegate(delegate)
|
42
|
+
@delegate = delegate
|
43
|
+
end
|
44
|
+
|
45
|
+
def build(&block)
|
46
|
+
# To construct the queue, we need the delegate.
|
47
|
+
delegate = @delegate
|
48
|
+
|
49
|
+
# We then wrap the delegate with the middleware in reverse order:
|
50
|
+
@dequeue.reverse_each do |middleware|
|
51
|
+
delegate = middleware.new(delegate)
|
52
|
+
end
|
53
|
+
|
54
|
+
# We can now construct the queue with the delegate:
|
55
|
+
producer = consumer = @queue.call(delegate)
|
56
|
+
|
57
|
+
# We now construct the queue producer:
|
58
|
+
@enqueue.reverse_each do |middleware|
|
59
|
+
producer = middleware.new(queue)
|
60
|
+
end
|
61
|
+
|
62
|
+
if block_given?
|
63
|
+
producer = yield(producer)
|
64
|
+
end
|
65
|
+
|
66
|
+
return Pipeline.new(producer, consumer, @delegate)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
module Coder
|
11
|
+
class JSON
|
12
|
+
def initialize
|
13
|
+
end
|
14
|
+
|
15
|
+
def dump(job)
|
16
|
+
::JSON.dump(job)
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(data)
|
20
|
+
::JSON.parse(data, symbolize_names: true)
|
21
|
+
end
|
22
|
+
|
23
|
+
DEFAULT = self.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'msgpack'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
module Coder
|
11
|
+
class Marshal
|
12
|
+
def dump(job)
|
13
|
+
::Marshal.dump(job)
|
14
|
+
end
|
15
|
+
|
16
|
+
def load(data)
|
17
|
+
::Marshal.load(data)
|
18
|
+
end
|
19
|
+
|
20
|
+
DEFAULT = self.new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'msgpack'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
module Coder
|
11
|
+
class MessagePack
|
12
|
+
def initialize
|
13
|
+
@factory = ::MessagePack::Factory.new
|
14
|
+
|
15
|
+
@factory.register_type(0x01, Symbol)
|
16
|
+
|
17
|
+
@factory.register_type(0x02, Time,
|
18
|
+
packer: ::MessagePack::Time::Packer,
|
19
|
+
unpacker: ::MessagePack::Time::Unpacker
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def dump(job)
|
24
|
+
@factory.pack(job)
|
25
|
+
end
|
26
|
+
|
27
|
+
def load(data)
|
28
|
+
@factory.unpack(data)
|
29
|
+
end
|
30
|
+
|
31
|
+
DEFAULT = self.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'coder/json'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Job
|
10
|
+
module Coder
|
11
|
+
DEFAULT = JSON::DEFAULT
|
12
|
+
|
13
|
+
# Type-cast for time values. See <https://bugs.ruby-lang.org/issues/20298> for background.
|
14
|
+
# @parameter value [Time || Integer || String || nil]
|
15
|
+
def self.Time(value)
|
16
|
+
case value
|
17
|
+
when ::Time
|
18
|
+
value
|
19
|
+
when Integer
|
20
|
+
::Time.at(value)
|
21
|
+
when String
|
22
|
+
::Time.new(value)
|
23
|
+
when nil
|
24
|
+
nil
|
25
|
+
else
|
26
|
+
value.to_time
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/async/job/generic.rb
CHANGED
@@ -10,13 +10,13 @@ module Async
|
|
10
10
|
self.new(...).enqueue
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(id,
|
13
|
+
def initialize(id, scheduled_at: nil)
|
14
14
|
@id = id
|
15
|
-
@
|
15
|
+
@scheduled_at = scheduled_at
|
16
16
|
end
|
17
17
|
|
18
18
|
attr :id
|
19
|
-
attr :
|
19
|
+
attr :scheduled_at
|
20
20
|
|
21
21
|
def serialize
|
22
22
|
raise NotImplementedError
|
data/lib/async/job/version.rb
CHANGED
data/lib/async/job.rb
CHANGED
data/readme.md
CHANGED
@@ -6,7 +6,11 @@ Provides an asynchronous job server.
|
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
9
|
-
|
9
|
+
Please see the [project documentation](https://socketry.github.io/async-job/) for more details.
|
10
|
+
|
11
|
+
- [Getting Started](https://socketry.github.io/async-job/guides/getting-started/index) - This guide gives you an overview of the `async-job` gem and explains the core concepts.
|
12
|
+
|
13
|
+
- [Redis Backend](https://socketry.github.io/async-job/guides/redis-backend/index) - This guide gives a brief overview of the implementation of the Redis backend.
|
10
14
|
|
11
15
|
## Contributing
|
12
16
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -37,7 +37,7 @@ cert_chain:
|
|
37
37
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
38
38
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
39
39
|
-----END CERTIFICATE-----
|
40
|
-
date: 2024-02-
|
40
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
41
41
|
dependencies:
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: async
|
@@ -75,12 +75,20 @@ extra_rdoc_files: []
|
|
75
75
|
files:
|
76
76
|
- lib/async/job.rb
|
77
77
|
- lib/async/job/backend.rb
|
78
|
+
- lib/async/job/backend/inline.rb
|
79
|
+
- lib/async/job/backend/inline/server.rb
|
78
80
|
- lib/async/job/backend/redis.rb
|
79
81
|
- lib/async/job/backend/redis/delayed_queue.rb
|
80
82
|
- lib/async/job/backend/redis/job_store.rb
|
81
83
|
- lib/async/job/backend/redis/processing_queue.rb
|
82
84
|
- lib/async/job/backend/redis/ready_queue.rb
|
83
85
|
- lib/async/job/backend/redis/server.rb
|
86
|
+
- lib/async/job/buffer.rb
|
87
|
+
- lib/async/job/builder.rb
|
88
|
+
- lib/async/job/coder.rb
|
89
|
+
- lib/async/job/coder/json.rb
|
90
|
+
- lib/async/job/coder/marshal.rb
|
91
|
+
- lib/async/job/coder/message_pack.rb
|
84
92
|
- lib/async/job/generic.rb
|
85
93
|
- lib/async/job/version.rb
|
86
94
|
- license.md
|
@@ -89,7 +97,7 @@ homepage:
|
|
89
97
|
licenses:
|
90
98
|
- MIT
|
91
99
|
metadata:
|
92
|
-
documentation_uri: https://socketry.github.io/async-job
|
100
|
+
documentation_uri: https://socketry.github.io/async-job/
|
93
101
|
post_install_message:
|
94
102
|
rdoc_options: []
|
95
103
|
require_paths:
|
metadata.gz.sig
CHANGED
Binary file
|