good_job 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9604c74cf4073b178401ec0cb606e55732f087464058bebe968b666c31c242d4
4
- data.tar.gz: f4af6118d55f231d15c3ffa2a3aac9f625911889a4f1adce5c14dcb2626af4d5
3
+ metadata.gz: 2c0fc31238c6d66b5b9ed3ddc0d4b9393a0a5a2cca85c7fcd0f2f24650892675
4
+ data.tar.gz: d6484d63b86eb7bc748b308cbfebe1ca7798fa1fa77d9542754dc99504f12244
5
5
  SHA512:
6
- metadata.gz: 46e92a0efba3937d274942ea55371f65cc3aa0451bc625bff6856be09525446960d192473548820bf1c289713151ee82e5cf1bdef21252da6a0927baafe5cc9c
7
- data.tar.gz: 9e1d108190398d5d698713e12ba981d63ee121f095185990f1f0963bee36e4f4760a22c9f64f8148624ba6be931a89943e48a601c4395ad825254d5d23c86c58
6
+ metadata.gz: 7e4d9fc5ae59750231906be49188aba712f1bdfbe2d66ed441f82c69ad267b0a056fed12998fe594c33c862f81d36d912a56d598c8e436e1e0ea225634abe66a
7
+ data.tar.gz: b02e2c08035b4a90713a0378e2b83173232baec7bf6b22ecbd56033d8fd38e78be0e3d992a7ca4e3339485014bc97fac62efd3d3fd94df195fceb9248703f004
data/README.md CHANGED
@@ -2,14 +2,34 @@
2
2
 
3
3
  GoodJob is a multithreaded, Postgres-based ActiveJob backend for Ruby on Rails.
4
4
 
5
+ Inspired by [Delayed::Job](https://github.com/collectiveidea/delayed_job) and [Que](https://github.com/que-rb/que), GoodJob’s design principles are:
6
+
7
+ - Stand on the shoulders of ActiveJob. For example, [exception](https://edgeguides.rubyonrails.org/active_job_basics.html#exceptions) and [retry](https://edgeguides.rubyonrails.org/active_job_basics.html#retrying-or-discarding-failed-jobs) behavior.
8
+ - Stand on the shoulders of Ruby on Rails. For example, ActiveRecord ORM, connection pools, and [multithreaded support](https://guides.rubyonrails.org/threading_and_code_execution.html) with [Concurrent-Ruby](https://github.com/ruby-concurrency/concurrent-ruby).
9
+ - Stand on the shoulders of Postgres. For example, Advisory Locks.
10
+ - Convention over simplicity over performance.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'good_job', github: 'bensheldon/good_job'
18
+ ```
19
+
20
+ And then execute:
21
+ ```bash
22
+ $ bundle
23
+ ```
24
+
5
25
  ## Usage
6
26
 
7
27
  1. Create a database migration:
8
28
  ```bash
9
- bin/rails g migration CreateGoodJobs
29
+ $ bin/rails g migration CreateGoodJobs
10
30
  ```
11
31
 
12
- And then add to the newly created file:
32
+ Add to the newly created migration file:
13
33
 
14
34
  ```ruby
15
35
  class CreateGoodJobs < ActiveRecord::Migration[6.0]
@@ -27,6 +47,13 @@ GoodJob is a multithreaded, Postgres-based ActiveJob backend for Ruby on Rails.
27
47
  end
28
48
  end
29
49
  ```
50
+
51
+ Run the migration:
52
+
53
+ ```bash
54
+ $ bin/rails db:migrate
55
+ ```
56
+
30
57
  1. Configure the ActiveJob adapter:
31
58
  ```ruby
32
59
  # config/environments/production.rb
@@ -41,18 +68,6 @@ GoodJob is a multithreaded, Postgres-based ActiveJob backend for Ruby on Rails.
41
68
  $ bundle exec good_job
42
69
  ```
43
70
 
44
- ## Installation
45
- Add this line to your application's Gemfile:
46
-
47
- ```ruby
48
- gem 'good_job', github: 'bensheldon/good_job'
49
- ```
50
-
51
- And then execute:
52
- ```bash
53
- $ bundle
54
- ```
55
-
56
71
  ## Development
57
72
 
58
73
  To run tests:
@@ -80,8 +95,31 @@ $ bundle install
80
95
  # => Using good_job 0.1.0 from https://github.com/bensheldon/good_job.git (at /Users/You/Projects/good_job@dc57fb0)
81
96
  ```
82
97
 
98
+ ## Releasing
99
+
100
+ Package maintainers can release this gem with the following [gem-release](https://github.com/svenfuchs/gem-release) command:
101
+
102
+ ```bash
103
+ # Sign into rubygems
104
+ $ gem signin
105
+
106
+ # Increase the version number
107
+ $ gem bump -v minor --no-commit
108
+
109
+ # Update the changelog
110
+ $ bundle exec changelog
111
+
112
+ # Commit the version and changelog to git
113
+ $ bundle commit_version
114
+
115
+ # Push to rubygems.org
116
+ $ gem release
117
+ ```
118
+
83
119
  ## Contributing
120
+
84
121
  Contribution directions go here.
85
122
 
86
123
  ## License
124
+
87
125
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -22,7 +22,14 @@ module GoodJob
22
22
  params[:scheduled_at] = Time.at(timestamp) if timestamp
23
23
 
24
24
  good_job = GoodJob::Job.create(params)
25
- @scheduler.enqueue(good_job) if inline?
25
+ job.provider_job_id = good_job.id
26
+
27
+ GoodJob.tag_logger do
28
+ ActiveSupport::Notifications.instrument("create.good_job", { good_job: good_job, job: job })
29
+ @scheduler.enqueue(good_job) if inline?
30
+ end
31
+
32
+ good_job
26
33
  end
27
34
 
28
35
  def shutdown(wait: true)
@@ -0,0 +1,60 @@
1
+ module GoodJob::Logging
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ cattr_accessor :logger, default: ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
6
+
7
+ def self.tag_logger(*tags)
8
+ if logger.respond_to?(:tagged)
9
+ tags.unshift "GoodJob" unless logger.formatter.current_tags.include?("GoodJob")
10
+ logger.tagged(*tags) { yield }
11
+ else
12
+ yield
13
+ end
14
+ end
15
+ end
16
+
17
+ class LogSubscriber < ActiveSupport::LogSubscriber
18
+ def create(event)
19
+ good_job = event.payload[:good_job]
20
+
21
+ info do
22
+ "Created GoodJob resource with id #{good_job.id}"
23
+ end
24
+ end
25
+
26
+ def timer_task_finished(event)
27
+ result = event.payload[:result]
28
+ exception = event.payload[:error]
29
+
30
+ if exception
31
+ error do
32
+ "ERROR: #{exception}\n #{exception.backtrace}"
33
+ end
34
+ end
35
+ end
36
+
37
+ def job_finished(event)
38
+ result = event.payload[:result]
39
+ exception = event.payload[:error]
40
+
41
+ if exception
42
+ error do
43
+ "ERROR: #{exception}\n #{exception.backtrace}"
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def logger
51
+ GoodJob.logger
52
+ end
53
+
54
+ def thread_name
55
+ Thread.current.name || Thread.current.object_id
56
+ end
57
+ end
58
+ end
59
+
60
+ GoodJob::Logging::LogSubscriber.attach_to :good_job
@@ -1,4 +1,7 @@
1
1
  module GoodJob
2
2
  class Railtie < ::Rails::Railtie
3
+ initializer "good_job.logger" do
4
+ ActiveSupport.on_load(:good_job) { self.logger = ::Rails.logger }
5
+ end
3
6
  end
4
7
  end
@@ -4,7 +4,7 @@ require "concurrent/utility/processor_counter"
4
4
 
5
5
  module GoodJob
6
6
  class Scheduler
7
- MINIMUM_EXECUTION_INTERVAL = 0.1
7
+ MAX_THREADS = Concurrent.processor_count
8
8
 
9
9
  DEFAULT_TIMER_OPTIONS = {
10
10
  execution_interval: 1,
@@ -12,16 +12,14 @@ module GoodJob
12
12
  run_now: true
13
13
  }.freeze
14
14
 
15
- MAX_THREADS = Concurrent.processor_count
16
-
17
15
  DEFAULT_POOL_OPTIONS = {
18
- name: 'good_job',
19
- min_threads: 0,
20
- max_threads: MAX_THREADS,
21
- auto_terminate: true,
22
- idletime: 0,
23
- max_queue: 0,
24
- fallback_policy: :abort # shouldn't matter -- 0 max queue
16
+ name: 'good_job',
17
+ min_threads: 0,
18
+ max_threads: MAX_THREADS,
19
+ auto_terminate: true,
20
+ idletime: 0,
21
+ max_queue: 0,
22
+ fallback_policy: :abort # shouldn't matter -- 0 max queue
25
23
  }.freeze
26
24
 
27
25
  def initialize(query = GoodJob::Job.all, **options)
@@ -30,13 +28,16 @@ module GoodJob
30
28
  @pool = Concurrent::ThreadPoolExecutor.new(DEFAULT_POOL_OPTIONS)
31
29
  @timer = Concurrent::TimerTask.new(DEFAULT_TIMER_OPTIONS) do
32
30
  idle_threads = @pool.max_length - @pool.length
33
- puts "There are idle_threads: #{idle_threads}"
34
31
  create_thread if idle_threads.positive?
35
- true
36
32
  end
33
+ @timer.add_observer(TimerObserver.new)
37
34
  @timer.execute
38
35
  end
39
36
 
37
+ def ordered_query
38
+ @query.where("scheduled_at < ?", Time.current).or(@query.where(scheduled_at: nil)).order(priority: :desc)
39
+ end
40
+
40
41
  def execute
41
42
  end
42
43
 
@@ -53,36 +54,31 @@ module GoodJob
53
54
  end
54
55
 
55
56
  def create_thread
56
- future = Concurrent::Future.new(args: [@query], executor: @pool) do |query|
57
+ future = Concurrent::Future.new(args: [ordered_query], executor: @pool) do |query|
57
58
  Rails.application.executor.wrap do
58
- thread_name = Thread.current.name || Thread.current.object_id
59
- while job = query.with_advisory_lock.first
60
- puts "Executing job #{job.id} in thread #{thread_name}"
59
+ while good_job = query.with_advisory_lock.first
60
+ ActiveSupport::Notifications.instrument("job_started.good_job", { good_job: good_job })
61
61
 
62
- JobWrapper.new(job).perform
62
+ JobWrapper.new(good_job).perform
63
63
 
64
- job.advisory_unlock
64
+ good_job.advisory_unlock
65
65
  end
66
- true
67
66
  end
67
+ true
68
68
  end
69
- future.add_observer(TaskObserver.new(self))
69
+ future.add_observer(TaskObserver.new)
70
70
  future.execute
71
71
  end
72
72
 
73
- class TaskObserver
74
- def initialize(scheduler)
75
- @scheduler = scheduler
73
+ class TimerObserver
74
+ def update(time, result, error)
75
+ ActiveSupport::Notifications.instrument("timer_task_finished.good_job", { result: result, error: error, time: time })
76
76
  end
77
+ end
77
78
 
78
- def update(time, result, ex)
79
- if result
80
- puts "(#{time}) Execution successfully returned #{result}\n"
81
- elsif ex.is_a?(Concurrent::TimeoutError)
82
- puts "(#{time}) Execution timed out\n"
83
- else
84
- puts "(#{time}) Execution failed with error #{result} #{ex}\n"
85
- end
79
+ class TaskObserver
80
+ def update(time, result, error)
81
+ ActiveSupport::Notifications.instrument("job_finished.good_job", { result: result, error: error, time: time })
86
82
  end
87
83
  end
88
84
  end
@@ -1,3 +1,3 @@
1
1
  module GoodJob
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/good_job.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require "rails"
2
+ require 'good_job/railtie'
2
3
 
4
+ require 'good_job/logging'
3
5
  require 'good_job/lockable'
4
6
  require 'good_job/job'
5
7
  require 'good_job/inline_scheduler'
@@ -8,5 +10,7 @@ require "good_job/job_wrapper"
8
10
  require 'good_job/adapter'
9
11
 
10
12
  module GoodJob
11
- # Your code goes here...
13
+ include Logging
14
+
15
+ ActiveSupport.run_load_hooks(:good_job, self)
12
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-03 00:00:00.000000000 Z
11
+ date: 2020-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: github_changelog_generator
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: pg
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -126,6 +140,7 @@ files:
126
140
  - lib/good_job/job.rb
127
141
  - lib/good_job/job_wrapper.rb
128
142
  - lib/good_job/lockable.rb
143
+ - lib/good_job/logging.rb
129
144
  - lib/good_job/railtie.rb
130
145
  - lib/good_job/scheduler.rb
131
146
  - lib/good_job/version.rb