async-job 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71fdcce6742cea5cfaeac68e800c56f1dbfa5ea6849503544c35912675874838
4
- data.tar.gz: a607a76328c14cee24618479efd1d6924adc5634d7a89d21df0ccccbea78b1d8
3
+ metadata.gz: 7381f7520a5ee41df3c93fc4f55c647952f10066868fcb22a196fb6ee807a1dd
4
+ data.tar.gz: a063193f2ff8a71fe798aadc3ce07d392fd2c53cadd5523cb20813fff9da2bdc
5
5
  SHA512:
6
- metadata.gz: 7bc8ac06036c862eb827af97ef43764dd44036dc14cdb5f988a294fc2dbbac5f441b32d71cd6551aa3000c190de82105fcce65771ced7b67d08a8f24e598c872
7
- data.tar.gz: 145098c24c1a115d018a4ecc8a1796aa295c4cfb85b8099c30c2e82c9a89fd31780e525015e799a12be807e748c824f299ac88677afdf0764f7b1594094b758e
6
+ metadata.gz: 56f1a056d2cbc2dab6a97226c07b6d2acec56de40bd95c302b652e4689c3fa08986a7b6f4e4c53a0ca15555c61695da6ef2219f8585d1c1006c01cacfffac50b
7
+ data.tar.gz: b0c62cf9b609beee163c948ff9fc933a1d82b3f0f611e555ddc4dadd4909ab3e0791e474ae7cdf35cb1081d12d38a5f73f37148945e2658bec07af31388b8480
checksums.yaml.gz.sig CHANGED
Binary file
@@ -3,11 +3,11 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
+ require_relative 'queue'
7
+
6
8
  module Async
7
9
  module Job
8
10
  class Builder
9
- Pipeline = Struct.new(:producer, :consumer, :delegate)
10
-
11
11
  def self.build(delegate = nil, &block)
12
12
  builder = self.new(delegate)
13
13
 
@@ -16,58 +16,48 @@ module Async
16
16
  return builder.build
17
17
  end
18
18
 
19
+ # @parameter delegate [Object] The initial delegate that will be wrapped by the queue.
19
20
  def initialize(delegate = nil)
21
+ # The client side middleware, in the order they should be applied to a job:
20
22
  @enqueue = []
23
+
24
+ # The server side middleware, in the order they should be applied to a job:
21
25
  @dequeue = []
22
- @delegate = delegate
23
26
 
24
- @queue = nil
25
- end
26
-
27
- def enqueue(middleware)
28
- @enqueue << middleware
27
+ # The output delegate, if any:
28
+ @delegate = delegate
29
29
  end
30
30
 
31
- def queue(queue, *arguments, **options)
32
- # The delegate is the output side of the queue, e.g. a Redis server delegate or similar wrapper.
33
- # The queue itself is instantiated with the delegate.
34
- @queue = ->(delegate){queue.new(delegate, *arguments, **options)}
31
+ def enqueue(middleware, ...)
32
+ @enqueue << ->(delegate){middleware.new(delegate, ...)}
35
33
  end
36
34
 
37
- def dequeue(middleware)
38
- @dequeue << middleware
35
+ def dequeue(middleware, ...)
36
+ @dequeue << ->(delegate){middleware.new(delegate, ...)}
39
37
  end
40
38
 
41
39
  def delegate(delegate)
42
40
  @delegate = delegate
43
41
  end
44
42
 
45
- def build(&block)
46
- # To construct the queue, we need the delegate.
47
- delegate = @delegate
48
-
43
+ def build(delegate = @delegate, &block)
49
44
  # We then wrap the delegate with the middleware in reverse order:
50
45
  @dequeue.reverse_each do |middleware|
51
- delegate = middleware.new(delegate)
46
+ delegate = middleware.call(delegate)
52
47
  end
53
48
 
54
- # We can now construct the queue with the delegate:
55
- if @queue
56
- producer = consumer = @queue.call(delegate)
57
- else
58
- producer = consumer = delegate
59
- end
49
+ client = server = delegate
60
50
 
61
51
  # We now construct the queue producer:
62
52
  @enqueue.reverse_each do |middleware|
63
- producer = middleware.new(producer)
53
+ client = middleware.call(client)
64
54
  end
65
55
 
66
56
  if block_given?
67
- producer = yield(producer) || producer
57
+ client = yield(client) || client
68
58
  end
69
59
 
70
- return Pipeline.new(producer, consumer, @delegate)
60
+ return Queue.new(client, server, @delegate)
71
61
  end
72
62
  end
73
63
  end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative 'generic'
7
+
8
+ require 'console/event/failure'
9
+
10
+ module Async
11
+ module Job
12
+ module Processor
13
+ class Aggregate < Generic
14
+ def initialize(delegate, parent: nil)
15
+ super(delegate)
16
+
17
+ @task = nil
18
+ @ready = Async::Condition.new
19
+
20
+ @pending = Array.new
21
+ @processing = Array.new
22
+ end
23
+
24
+ def flush(jobs)
25
+ while job = jobs.shift
26
+ @delegate.call(job)
27
+ end
28
+ rescue => error
29
+ Console::Event::Failure.for(error).emit(self, "Could not flush #{jobs.size} jobs.")
30
+ end
31
+
32
+ def run(task)
33
+ while true
34
+ while @pending.empty?
35
+ @ready.wait
36
+ end
37
+
38
+ task.defer_stop do
39
+ # Swap the buffers:
40
+ @pending, @processing = @processing, @pending
41
+
42
+ flush(@processing)
43
+ end
44
+ end
45
+ end
46
+
47
+ # Start the background processing task if it is not already running.
48
+ #
49
+ # @return [Boolean] true if the task was started, false if it was already running.
50
+ protected def start!(parent: Async::Task.current)
51
+ return false if @task
52
+
53
+ # We are creating a task:
54
+ @task = true
55
+
56
+ parent.async(transient: true, annotation: self.class.name) do |task|
57
+ @task = task
58
+
59
+ run(task)
60
+ ensure
61
+ # Ensure that all jobs are flushed before we exit:
62
+ flush(@processing) if @processing.any?
63
+ flush(@pending) if @pending.any?
64
+ @task = nil
65
+ end
66
+
67
+ return true
68
+ end
69
+
70
+ # Enqueue a job into the pending buffer.
71
+ #
72
+ # Start the background processing task if it is not already running.
73
+ def call(job)
74
+ @pending << job
75
+
76
+ start! or @ready.signal
77
+ end
78
+
79
+ def start
80
+ super
81
+
82
+ self.start!
83
+ end
84
+
85
+ def stop
86
+ @task&.stop
87
+
88
+ super
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative 'generic'
7
+
8
+ require 'console/event/failure'
9
+
10
+ module Async
11
+ module Job
12
+ module Processor
13
+ # Add a small processing delay to each job.
14
+ class Delayed < Generic
15
+ def initialize(delegate, delay: 0.1)
16
+ super(delegate)
17
+
18
+ @delay = delay
19
+ end
20
+
21
+ def call(job)
22
+ sleep(@delay)
23
+
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
29
+ 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
+ module Async
7
+ module Job
8
+ module Processor
9
+ class Generic
10
+ def initialize(delegate = nil)
11
+ @delegate = delegate
12
+ end
13
+
14
+ def call(job)
15
+ @delegate.call(job)
16
+ end
17
+
18
+ def start
19
+ @delegate.start
20
+ end
21
+
22
+ def stop
23
+ @delegate.stop
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative '../coder'
7
+ require_relative 'generic'
8
+
9
+ require 'async/idler'
10
+
11
+ module Async
12
+ module Job
13
+ module Processor
14
+ class Inline < Generic
15
+ def initialize(delegate, parent: nil)
16
+ super(delegate)
17
+
18
+ @parent = parent || Async::Idler.new
19
+ end
20
+
21
+ def call(job)
22
+ scheduled_at = Coder::Time(job["scheduled_at"])
23
+
24
+ @parent.async do
25
+ if scheduled_at
26
+ sleep(scheduled_at - Time.now)
27
+ end
28
+
29
+ @delegate.call(job)
30
+ rescue => error
31
+ Console.error(self, error)
32
+ end
33
+ end
34
+
35
+ def start
36
+ @delegate&.start
37
+ end
38
+
39
+ def stop
40
+ @delegate&.stop
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -5,9 +5,9 @@
5
5
 
6
6
  module Async
7
7
  module Job
8
- module Backend
8
+ module Processor
9
9
  module Redis
10
- class DelayedQueue
10
+ class DelayedJobs
11
11
  ADD = <<~LUA
12
12
  redis.call('HSET', KEYS[1], ARGV[1], ARGV[2])
13
13
  redis.call('ZADD', KEYS[2], ARGV[3], ARGV[1])
@@ -30,15 +30,13 @@ module Async
30
30
  @move = @client.script(:load, MOVE)
31
31
  end
32
32
 
33
- def start(ready_queue, resolution: 10, parent: Async::Task.current)
34
- Console.info(self, "Starting delayed queue...")
33
+ def start(ready_list, resolution: 10, parent: Async::Task.current)
35
34
  parent.async do
36
35
  while true
37
- Console.debug(self, "Checking for delayed jobs...")
38
- count = move(destination: ready_queue.key)
36
+ count = move(destination: ready_list.key)
39
37
 
40
38
  if count > 0
41
- Console.info(self, "Moved #{count} delayed jobs to ready queue.")
39
+ Console.debug(self, "Moved #{count} delayed jobs to ready list.")
42
40
  end
43
41
 
44
42
  sleep(resolution)
@@ -5,7 +5,7 @@
5
5
 
6
6
  module Async
7
7
  module Job
8
- module Backend
8
+ module Processor
9
9
  module Redis
10
10
  class JobStore
11
11
  def initialize(client, key)
@@ -5,9 +5,9 @@
5
5
 
6
6
  module Async
7
7
  module Job
8
- module Backend
8
+ module Processor
9
9
  module Redis
10
- class ProcessingQueue
10
+ class ProcessingList
11
11
  REQUEUE = <<~LUA
12
12
  local cursor = "0"
13
13
  local count = 0
@@ -50,12 +50,12 @@ module Async
50
50
  redis.call('HDEL', KEYS[2], ARGV[1])
51
51
  LUA
52
52
 
53
- def initialize(client, key, id, ready_queue, job_store)
53
+ def initialize(client, key, id, ready_list, job_store)
54
54
  @client = client
55
55
  @key = key
56
56
  @id = id
57
57
 
58
- @ready_queue = ready_queue
58
+ @ready_list = ready_list
59
59
  @job_store = job_store
60
60
 
61
61
  @pending_key = "#{@key}:#{@id}:pending"
@@ -69,7 +69,7 @@ module Async
69
69
  attr :key
70
70
 
71
71
  def fetch
72
- @client.brpoplpush(@ready_queue.key, @pending_key, 0)
72
+ @client.brpoplpush(@ready_list.key, @pending_key, 0)
73
73
  end
74
74
 
75
75
  def complete(id)
@@ -79,22 +79,20 @@ module Async
79
79
 
80
80
  def retry(id)
81
81
  Console.warn(self, "Retrying job: #{id}")
82
- @client.evalsha(@retry, 2, @pending_key, @ready_queue.key, id)
82
+ @client.evalsha(@retry, 2, @pending_key, @ready_list.key, id)
83
83
  end
84
84
 
85
85
  def start(delay: 5, factor: 2, parent: Async::Task.current)
86
86
  heartbeat_key = "#{@key}:#{@id}"
87
87
  start_time = Time.now.to_f
88
88
 
89
- Console.info(self, "Starting processing queue...", key: @key, id: @id, heartbeat_key: heartbeat_key, delay: delay, factor: factor)
90
-
91
89
  parent.async do
92
90
  while true
93
91
  uptime = (Time.now.to_f - start_time).round(2)
94
92
  @client.set(heartbeat_key, JSON.dump(uptime: uptime), seconds: delay*factor)
95
93
 
96
- # Requeue any jobs that have been abandoned:
97
- count = @client.evalsha(@requeue, 2, @key, @ready_queue.key)
94
+ # REQUEUE any jobs that have been abandoned:
95
+ count = @client.evalsha(@requeue, 2, @key, @ready_list.key)
98
96
  if count > 0
99
97
  Console.warn(self, "Requeued #{count} abandoned jobs.")
100
98
  end
@@ -5,9 +5,9 @@
5
5
 
6
6
  module Async
7
7
  module Job
8
- module Backend
8
+ module Processor
9
9
  module Redis
10
- class ReadyQueue
10
+ class ReadyList
11
11
  ADD = <<~LUA
12
12
  redis.call('HSET', KEYS[1], ARGV[1], ARGV[2])
13
13
  redis.call('LPUSH', KEYS[2], ARGV[1])
@@ -3,22 +3,23 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative 'delayed_queue'
6
+ require_relative 'delayed_jobs'
7
7
  require_relative 'job_store'
8
- require_relative 'processing_queue'
9
- require_relative 'ready_queue'
8
+ require_relative 'processing_list'
9
+ require_relative 'ready_list'
10
10
  require_relative '../../coder'
11
+ require_relative '../generic'
11
12
 
12
13
  require 'securerandom'
13
14
  require 'async/idler'
14
15
 
15
16
  module Async
16
17
  module Job
17
- module Backend
18
+ module Processor
18
19
  module Redis
19
- class Server
20
+ class Server < Generic
20
21
  def initialize(delegate, client, prefix: 'async-job', coder: Coder::DEFAULT, resolution: 10, parent: nil)
21
- @delegate = delegate
22
+ super(delegate)
22
23
 
23
24
  @id = SecureRandom.uuid
24
25
  @client = client
@@ -27,11 +28,9 @@ module Async
27
28
  @resolution = resolution
28
29
 
29
30
  @job_store = JobStore.new(@client, "#{@prefix}:jobs")
30
-
31
- @delayed_queue = DelayedQueue.new(@client, "#{@prefix}:delayed")
32
- @ready_queue = ReadyQueue.new(@client, "#{@prefix}:ready")
33
-
34
- @processing_queue = ProcessingQueue.new(@client, "#{@prefix}:processing", @id, @ready_queue, @job_store)
31
+ @delayed_jobs = DelayedJobs.new(@client, "#{@prefix}:delayed")
32
+ @ready_list = ReadyList.new(@client, "#{@prefix}:ready")
33
+ @processing_list = ProcessingList.new(@client, "#{@prefix}:processing", @id, @ready_list, @job_store)
35
34
 
36
35
  @parent = parent || Async::Idler.new
37
36
  end
@@ -53,49 +52,50 @@ module Async
53
52
  end
54
53
 
55
54
  def start
56
- @delegate&.start
55
+ super
57
56
 
58
- # Start the delayed queue, which will move jobs to the ready queue when they are ready:
59
- @delayed_queue.start(@ready_queue, resolution: @resolution)
57
+ # Start the delayed processor, which will move jobs to the ready processor when they are ready:
58
+ @delayed_jobs.start(@ready_list, resolution: @resolution)
60
59
 
61
- # Start the processing queue, which will move jobs to the ready queue when they are abandoned:
62
- @processing_queue.start
60
+ # Start the processing processor, which will move jobs to the ready processor when they are abandoned:
61
+ @processing_list.start
63
62
 
64
63
  self.start!
65
64
  end
66
65
 
67
66
  def stop
68
67
  @task&.stop
69
- @delegate&.stop
68
+
69
+ super
70
70
  end
71
71
 
72
72
  def call(job)
73
73
  scheduled_at = Coder::Time(job["scheduled_at"])
74
74
 
75
75
  if scheduled_at
76
- @delayed_queue.add(@coder.dump(job), scheduled_at, @job_store)
76
+ @delayed_jobs.add(@coder.dump(job), scheduled_at, @job_store)
77
77
  else
78
- @ready_queue.add(@coder.dump(job), @job_store)
78
+ @ready_list.add(@coder.dump(job), @job_store)
79
79
  end
80
80
  end
81
81
 
82
82
  protected
83
83
 
84
84
  def dequeue(parent)
85
- _id = @processing_queue.fetch
85
+ _id = @processing_list.fetch
86
86
 
87
87
  parent.async do
88
88
  id = _id; _id = nil
89
89
 
90
90
  job = @coder.load(@job_store.get(id))
91
91
  @delegate.call(job)
92
- @processing_queue.complete(id)
92
+ @processing_list.complete(id)
93
93
  rescue => error
94
- @processing_queue.retry(id)
94
+ @processing_list.retry(id)
95
95
  Console.error(self, error)
96
96
  end
97
97
  ensure
98
- @processing_queue.retry(_id) if _id
98
+ @processing_list.retry(_id) if _id
99
99
  end
100
100
  end
101
101
  end
@@ -8,7 +8,7 @@ require 'async/redis/client'
8
8
 
9
9
  module Async
10
10
  module Job
11
- module Backend
11
+ module Processor
12
12
  module Redis
13
13
  def self.new(delegate, endpoint: Async::Redis.local_endpoint, **options)
14
14
  client = Async::Redis::Client.new(endpoint)
@@ -3,15 +3,13 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative 'inline/server'
6
+ require_relative 'processor/inline'
7
7
 
8
8
  module Async
9
9
  module Job
10
- module Backend
11
- module Inline
12
- def self.new(delegate)
13
- return Server.new(delegate)
14
- end
10
+ module Processor
11
+ def self.new(processor: Inline, **options)
12
+ processor.new(**options)
15
13
  end
16
14
  end
17
15
  end
@@ -0,0 +1,32 @@
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 Queue
9
+ def initialize(client, server, delegate)
10
+ @client = client
11
+ @server = server
12
+ @delegate = delegate
13
+ end
14
+
15
+ attr :client
16
+ attr :server
17
+ attr :delegate
18
+
19
+ def call(...)
20
+ @client.call(...)
21
+ end
22
+
23
+ def start
24
+ @server.start
25
+ end
26
+
27
+ def stop
28
+ @server.stop
29
+ end
30
+ end
31
+ end
32
+ end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module Job
8
- VERSION = "0.8.0"
8
+ VERSION = "0.9.0"
9
9
  end
10
10
  end
data/lib/async/job.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'job/version'
7
- require_relative 'job/backend'
7
+ require_relative 'job/queue'
8
8
  require_relative 'job/builder'
data/readme.md CHANGED
@@ -10,7 +10,7 @@ Please see the [project documentation](https://socketry.github.io/async-job/) fo
10
10
 
11
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
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.
13
+ - [Redis Processor](https://socketry.github.io/async-job/guides/redis-processor/index) - This guide gives a brief overview of the implementation of the Redis queue.
14
14
 
15
15
  ## See Also
16
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.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -75,23 +75,24 @@ extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
77
  - lib/async/job.rb
78
- - lib/async/job/backend.rb
79
- - lib/async/job/backend/aggregate.rb
80
- - lib/async/job/backend/aggregate/server.rb
81
- - lib/async/job/backend/inline.rb
82
- - lib/async/job/backend/inline/server.rb
83
- - lib/async/job/backend/redis.rb
84
- - lib/async/job/backend/redis/delayed_queue.rb
85
- - lib/async/job/backend/redis/job_store.rb
86
- - lib/async/job/backend/redis/processing_queue.rb
87
- - lib/async/job/backend/redis/ready_queue.rb
88
- - lib/async/job/backend/redis/server.rb
89
78
  - lib/async/job/buffer.rb
90
79
  - lib/async/job/builder.rb
91
80
  - lib/async/job/coder.rb
92
81
  - lib/async/job/coder/marshal.rb
93
82
  - lib/async/job/coder/message_pack.rb
94
83
  - lib/async/job/generic.rb
84
+ - lib/async/job/processor.rb
85
+ - lib/async/job/processor/aggregate.rb
86
+ - lib/async/job/processor/delayed.rb
87
+ - lib/async/job/processor/generic.rb
88
+ - lib/async/job/processor/inline.rb
89
+ - lib/async/job/processor/redis.rb
90
+ - lib/async/job/processor/redis/delayed_jobs.rb
91
+ - lib/async/job/processor/redis/job_store.rb
92
+ - lib/async/job/processor/redis/processing_list.rb
93
+ - lib/async/job/processor/redis/ready_list.rb
94
+ - lib/async/job/processor/redis/server.rb
95
+ - lib/async/job/queue.rb
95
96
  - lib/async/job/version.rb
96
97
  - license.md
97
98
  - readme.md
metadata.gz.sig CHANGED
Binary file
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2024, by Samuel Williams.
5
-
6
- require 'console/event/failure'
7
-
8
- module Async
9
- module Job
10
- module Backend
11
- module Aggregate
12
- class Server
13
- def initialize(delegate, parent: nil)
14
- @delegate = delegate
15
-
16
- @task = nil
17
- @ready = Async::Condition.new
18
-
19
- @pending = Array.new
20
- @processing = Array.new
21
- end
22
-
23
- def flush(jobs)
24
- while job = jobs.shift
25
- @delegate.call(job)
26
- end
27
- rescue => error
28
- Console::Event::Failure.for(error).emit(self, "Could not flush #{jobs.size} jobs.")
29
- end
30
-
31
- def run(task)
32
- while true
33
- while @pending.empty?
34
- @ready.wait
35
- end
36
-
37
- task.defer_stop do
38
- # Swap the buffers:
39
- @pending, @processing = @processing, @pending
40
-
41
- flush(@processing)
42
- end
43
- end
44
- end
45
-
46
- # Start the background processing task if it is not already running.
47
- #
48
- # @return [Boolean] true if the task was started, false if it was already running.
49
- protected def start!(parent: Async::Task.current)
50
- return false if @task
51
-
52
- # We are creating a task:
53
- @task = true
54
-
55
- parent.async(transient: true, annotation: self.class.name) do |task|
56
- @task = task
57
-
58
- run(task)
59
- ensure
60
- # Ensure that all jobs are flushed before we exit:
61
- flush(@processing) if @processing.any?
62
- flush(@pending) if @pending.any?
63
- @task = nil
64
- end
65
-
66
- return true
67
- end
68
-
69
- # Enqueue a job into the pending buffer.
70
- #
71
- # Start the background processing task if it is not already running.
72
- def call(job)
73
- @pending << job
74
-
75
- start! or @ready.signal
76
- end
77
-
78
- def start
79
- @delegate&.start
80
- self.start!
81
- end
82
-
83
- def stop
84
- @task&.stop
85
- @delegate&.stop
86
- end
87
- end
88
- end
89
- end
90
- end
91
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2024, by Samuel Williams.
5
-
6
- require_relative 'aggregate/server'
7
-
8
- module Async
9
- module Job
10
- module Backend
11
- module Aggregate
12
- def self.new(delegate)
13
- return Server.new(delegate)
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,45 +0,0 @@
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
- require 'async/idler'
9
-
10
- module Async
11
- module Job
12
- module Backend
13
- module Inline
14
- class Server
15
- def initialize(delegate, parent: nil)
16
- @delegate = delegate
17
- @parent = parent || Async::Idler.new
18
- end
19
-
20
- def call(job)
21
- scheduled_at = Coder::Time(job["scheduled_at"])
22
-
23
- @parent.async do
24
- if scheduled_at
25
- sleep(scheduled_at - Time.now)
26
- end
27
-
28
- @delegate.call(job)
29
- rescue => error
30
- Console.error(self, error)
31
- end
32
- end
33
-
34
- def start
35
- @delegate&.start
36
- end
37
-
38
- def stop
39
- @delegate&.stop
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2024, by Samuel Williams.
5
-
6
- require_relative 'backend/redis'
7
-
8
- module Async
9
- module Job
10
- module Backend
11
- def self.new(backend: Async::Job::Backend::Redis, **options)
12
- backend.new(**options)
13
- end
14
- end
15
- end
16
- end