async-job-adapter-active_job 0.12.1 → 0.14.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: 5d1cb1e42e12edd769d1cabbd69b95db8332178ec952275e2e587fb8d4679c29
4
- data.tar.gz: 4c560b3d759812bcef27293441528077b4dfc4278399519d802d5c097f8ba710
3
+ metadata.gz: 2dd9f7593bc4e508c98ca5cff8a163fc594872625467667138213a3ab8f2ed78
4
+ data.tar.gz: 78d52a6b38482a80ee4c227d8f753baa2662d313d6a59e284f35de2e00b84e32
5
5
  SHA512:
6
- metadata.gz: 486fa0105ecf07506ae2c807e6c1d7f013d2d4bcd11df00c703143a8379cd6abc0a46b8532ef24abe960cd598aeb8ecdd5fb63e397a516bbbca199eb5d016428
7
- data.tar.gz: eae87108c3e46b892f086cf39f1359888e3938c8127e9e39f716bf2c05bb89bb6f284844f643a004122845150861467153892c98984d43677393db1964cfdab5
6
+ metadata.gz: f205bafb6e23f4eed08575db38d96ec18e4f7e9bad444830b03b6e5a33fac62d91749f0e2ab4bf0328a2fa5192ee19bbdcf182c792de83464555871112674e26
7
+ data.tar.gz: e239ac52ec5e7bfae69347c3dcedd4cb0d6dffae60114bcdad4e3c3528c66a49b1bf2c2e4b940ea447b631abb028192336aab1e81b6806fdb7a3539118b532c8
checksums.yaml.gz.sig CHANGED
Binary file
@@ -7,13 +7,8 @@ require 'async/service/controller'
7
7
  require 'async/job/adapter/active_job/environment'
8
8
 
9
9
  configuration = Async::Service::Configuration.build do
10
- service "async-job-server" do
10
+ service "async-job-adapter-active_job-server" do
11
11
  include Async::Job::Adapter::ActiveJob::Environment
12
-
13
- root {ENV.fetch('RAILS_ROOT', Dir.pwd)}
14
-
15
- # If you have multiple queues, you may want to run a separate server for each queue.
16
- queue_name ENV.fetch('ASYNC_JOB_ADAPTER_ACTIVE_JOB_QUEUE_NAME', 'default')
17
12
  end
18
13
  end
19
14
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require 'active_job/queue_adapters/abstract_adapter'
7
+
8
+ module ActiveJob
9
+ module QueueAdapters
10
+ class AsyncJobAdapter < AbstractAdapter
11
+ def initialize(dispatcher = ::Async::Job::Adapter::ActiveJob::Railtie.dispatcher)
12
+ @dispatcher = dispatcher
13
+ end
14
+
15
+ # Enqueue a job for processing.
16
+ def enqueue(job)
17
+ @dispatcher.call(job)
18
+ end
19
+
20
+ # Enqueue a job for processing at a specific time.
21
+ def enqueue_at(job, timestamp)
22
+ @dispatcher.call(job)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -4,10 +4,8 @@
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'executor'
7
- require_relative 'interface'
8
7
 
9
8
  require 'async/job'
10
- require 'thread/local'
11
9
  require 'async/job/builder'
12
10
 
13
11
  module Async
@@ -41,18 +39,10 @@ module Async
41
39
  end
42
40
  end
43
41
 
44
- # Enqueue a job for processing.
45
- def enqueue(job)
42
+ def call(job)
46
43
  name = @aliases.fetch(job.queue_name, job.queue_name)
47
44
 
48
- self[name].client.enqueue(job)
49
- end
50
-
51
- # Enqueue a job for processing at a specific time.
52
- def enqueue_at(job, timestamp)
53
- name = @aliases.fetch(job.queue_name, job.queue_name)
54
-
55
- self[name].client.enqueue_at(job, timestamp)
45
+ self[name].client.call(job.serialize)
56
46
  end
57
47
 
58
48
  # Start processing jobs in the given queue.
@@ -60,17 +50,16 @@ module Async
60
50
  self[name].server.start
61
51
  end
62
52
 
53
+ def keys
54
+ @definitions.keys
55
+ end
56
+
63
57
  private def build(definition)
64
58
  builder = Builder.new(Executor::DEFAULT)
65
59
 
66
60
  builder.instance_eval(&definition)
67
61
 
68
- builder.build do |client|
69
- # Ensure that the client is an interface:
70
- unless client.is_a?(Interface)
71
- Interface.new(client)
72
- end
73
- end
62
+ return builder.build
74
63
  end
75
64
  end
76
65
  end
@@ -16,9 +16,21 @@ module Async
16
16
  Service
17
17
  end
18
18
 
19
+ def root
20
+ ENV.fetch('RAILS_ROOT', Dir.pwd)
21
+ end
22
+
23
+ def dispatcher
24
+ Railtie.dispatcher
25
+ end
26
+
19
27
  # The name of the queue to use.
20
- def queue_name
21
- "default"
28
+ def queue_names
29
+ if queue_names = ENV['ASYNC_JOB_ADAPTER_ACTIVE_JOB_QUEUE_NAMES']
30
+ queue_names.split(',')
31
+ else
32
+ dispatcher.keys
33
+ end
22
34
  end
23
35
  end
24
36
  end
@@ -5,6 +5,12 @@
5
5
 
6
6
  require 'json'
7
7
 
8
+ require 'console'
9
+ require 'console/event/failure'
10
+
11
+ require 'active_job'
12
+ require 'active_job/base'
13
+
8
14
  module Async
9
15
  module Job
10
16
  module Adapter
@@ -15,15 +21,26 @@ module Async
15
21
  @delegate = delegate
16
22
  end
17
23
 
24
+ def execute(job_data)
25
+ ::ActiveJob::Callbacks.run_callbacks(:execute) do
26
+ job = ::ActiveJob::Base.deserialize(job_data)
27
+
28
+ begin
29
+ job.perform_now
30
+ rescue => error
31
+ # Ignore, as ActiveJob has already logged the error.
32
+ end
33
+ end
34
+ end
35
+
18
36
  # Execute the given job.
19
37
  def call(job)
20
- Console.debug(self, "Executing job...", job: job)
21
38
  begin
22
- ::ActiveJob::Base.execute(job)
39
+ execute(job)
23
40
  rescue => error
24
41
  # Error handling is done by the job itself.
25
42
  # Ignore the error here, as ActiveJob has already logged unhandled errors.
26
- # Console::Event::Failure.for(error).emit(self, "Failed to execute job!", job: job)
43
+ Console::Event::Failure.for(error).emit(self, "Failed to execute job!", job: job)
27
44
  end
28
45
 
29
46
  @delegate&.call(job)
@@ -6,11 +6,7 @@
6
6
  require 'async/job'
7
7
  require 'async/job/processor/inline'
8
8
 
9
- require 'thread/local'
10
-
11
- require_relative 'dispatcher'
12
-
13
- Thread.attr_accessor :async_job_adapter_active_job_dispatcher
9
+ require_relative 'thread_local_dispatcher'
14
10
 
15
11
  module Async
16
12
  module Job
@@ -26,6 +22,8 @@ module Async
26
22
  def initialize
27
23
  @definitions = {"default" => DEFAULT_QUEUE_DEFINITION}
28
24
  @aliases = {}
25
+
26
+ @dispatcher = ThreadLocalDispatcher.new(@definitions, @aliases)
29
27
  end
30
28
 
31
29
  # The queues that are available for processing jobs.
@@ -34,6 +32,9 @@ module Async
34
32
  # The aliases for the definitions, if any.
35
33
  attr :aliases
36
34
 
35
+ # Thed default dispatcher for processing jobs.
36
+ attr :dispatcher
37
+
37
38
  # Define a new backend for processing jobs.
38
39
  # @parameter name [String] The name of the backend.
39
40
  # @parameter aliases [Array(String)] The aliases for the backend.
@@ -57,45 +58,12 @@ module Async
57
58
  end
58
59
  end
59
60
 
60
- # Used for dispatching jobs to a thread-local queue to avoid thread-safety issues.
61
- class ThreadLocalDispatcher
62
- def initialize(definitions, aliases)
63
- @definitions = definitions
64
- @aliases = aliases
65
- end
66
-
67
- # The dispatcher for the current thread.
68
- def dispatcher
69
- Thread.current.async_job_adapter_active_job_dispatcher ||= Dispatcher.new(@definitions, @aliases)
70
- end
71
-
72
- # Enqueue a job to be processed at a specific time.
73
- def enqueue_at(job, timestamp)
74
- dispatcher.enqueue_at(job, timestamp)
75
- end
76
-
77
- # Enqueue a job to be processed as soon as possible.
78
- def enqueue(job)
79
- dispatcher.enqueue(job)
80
- end
81
-
82
- # Start processing jobs in the queue with the given name.
83
- # @parameter name [String] The name of the queue.
84
- def start(name)
85
- dispatcher.start(name)
86
- end
87
- end
88
-
89
61
  # Start the job server with the given name.
90
62
  def start(name = "default")
91
- config.active_job.queue_adapter.start(name)
63
+ @dispatcher.start(name)
92
64
  end
93
65
 
94
- DEFAULT_DISPATCHER = ThreadLocalDispatcher.new(self.definitions, self.aliases)
95
-
96
66
  config.async_job = self
97
-
98
- config.active_job.queue_adapter = DEFAULT_DISPATCHER
99
67
  end
100
68
  end
101
69
  end
@@ -4,6 +4,8 @@
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
6
  require 'async/service/generic'
7
+ require 'console/event/failure'
8
+ require 'async/barrier'
7
9
 
8
10
  module Async
9
11
  module Job
@@ -15,12 +17,29 @@ module Async
15
17
  def setup(container)
16
18
  container.run(name: self.name, restart: true) do |instance|
17
19
  evaluator = @environment.evaluator
20
+
18
21
  require File.expand_path('config/environment', evaluator.root)
19
22
 
23
+ dispatcher = evaluator.dispatcher
24
+
20
25
  instance.ready!
21
26
 
22
- Sync do
23
- Railtie.start(evaluator.queue_name)
27
+ Sync do |task|
28
+ barrier = Async::Barrier.new
29
+
30
+ # Start all the named queues:
31
+ evaluator.queue_names.each do |queue_name|
32
+ barrier.async do
33
+ Console.debug(self, "Starting queue...", queue_name: queue_name)
34
+ dispatcher.start(queue_name)
35
+ rescue => error
36
+ Console::Event::Failure.for(error).emit(self, "Queue failed!")
37
+ end
38
+ end
39
+
40
+ barrier.wait
41
+ ensure
42
+ barrier.stop
24
43
  end
25
44
  end
26
45
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative 'dispatcher'
7
+
8
+ Thread.attr_accessor :async_job_adapter_active_job_dispatcher
9
+
10
+ module Async
11
+ module Job
12
+ module Adapter
13
+ module ActiveJob
14
+ # Used for dispatching jobs to a thread-local queue to avoid thread-safety issues.
15
+ class ThreadLocalDispatcher
16
+ def initialize(definitions, aliases)
17
+ @definitions = definitions
18
+ @aliases = aliases
19
+ end
20
+
21
+ # @attribute [Hash(String, Proc)] The definitions to use for creating queues.
22
+ attr :definitions
23
+
24
+ # @attribute [Hash(String, String)] The aliases for the job queues.
25
+ attr :aliases
26
+
27
+ # The dispatcher for the current thread.
28
+ #
29
+ # As a dispatcher contains state, it is important to ensure that each thread has its own dispatcher.
30
+ def dispatcher
31
+ Thread.current.async_job_adapter_active_job_dispatcher ||= Dispatcher.new(@definitions, @aliases)
32
+ end
33
+
34
+ def [](name)
35
+ dispatcher[name]
36
+ end
37
+
38
+ def call(job)
39
+ dispatcher.call(job)
40
+ end
41
+
42
+ # Start processing jobs in the queue with the given name.
43
+ # @parameter name [String] The name of the queue.
44
+ def start(name)
45
+ dispatcher.start(name)
46
+ end
47
+
48
+ # The names of all the queues that are available for processing jobs.
49
+ def keys
50
+ @definitions.keys
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -7,7 +7,7 @@ module Async
7
7
  module Job
8
8
  module Adapter
9
9
  module ActiveJob
10
- VERSION = "0.12.1"
10
+ VERSION = "0.14.0"
11
11
  end
12
12
  end
13
13
  end
@@ -3,7 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative 'active_job/version'
7
- require_relative 'active_job/interface'
8
- require_relative 'active_job/executor'
9
- require_relative "active_job/railtie" if defined?(Rails::Railtie)
6
+ require_relative "active_job/version"
7
+ require_relative "active_job/executor"
8
+
9
+ if defined?(Rails::Railtie)
10
+ require_relative "active_job/railtie"
11
+ require "active_job/queue_adapters/async_job_adapter"
12
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-job-adapter-active_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.14.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-08-09 00:00:00.000000000 Z
40
+ date: 2024-08-11 00:00:00.000000000 Z
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: async-job
@@ -67,20 +67,6 @@ dependencies:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0.12'
70
- - !ruby/object:Gem::Dependency
71
- name: thread-local
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: '0'
77
- type: :runtime
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- version: '0'
84
70
  description:
85
71
  email:
86
72
  executables:
@@ -89,13 +75,14 @@ extensions: []
89
75
  extra_rdoc_files: []
90
76
  files:
91
77
  - bin/async-job-adapter-active_job-server
78
+ - lib/active_job/queue_adapters/async_job_adapter.rb
92
79
  - lib/async/job/adapter/active_job.rb
93
80
  - lib/async/job/adapter/active_job/dispatcher.rb
94
81
  - lib/async/job/adapter/active_job/environment.rb
95
82
  - lib/async/job/adapter/active_job/executor.rb
96
- - lib/async/job/adapter/active_job/interface.rb
97
83
  - lib/async/job/adapter/active_job/railtie.rb
98
84
  - lib/async/job/adapter/active_job/service.rb
85
+ - lib/async/job/adapter/active_job/thread_local_dispatcher.rb
99
86
  - lib/async/job/adapter/active_job/version.rb
100
87
  - license.md
101
88
  - readme.md
metadata.gz.sig CHANGED
Binary file
@@ -1,38 +0,0 @@
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 Adapter
9
- module ActiveJob
10
- # An interface for `ActiveJob` that allows you to use `Async::Job` as the queue.
11
- class Interface
12
- def initialize(delegate)
13
- @delegate = delegate
14
- end
15
-
16
- # Enqueue a job for processing.
17
- def enqueue(job)
18
- Console.debug(self, "Enqueueing job...", id: job.job_id)
19
- @delegate.call(serialize(job))
20
- end
21
-
22
- # Enqueue a job for processing at a specific time.
23
- def enqueue_at(job, timestamp)
24
- # We assume the given timestamp is the same as `job.scheduled_at` which is true in every case we've seen so far.
25
- Console.debug(self, "Scheduling job...", id: job.job_id, scheduled_at: job.scheduled_at)
26
- @delegate.call(serialize(job))
27
- end
28
-
29
- protected
30
-
31
- def serialize(job)
32
- job.serialize
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end