good_job 1.0.2 → 1.1.3

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: f7c64e8766a52e6bbbb5e55b409bb0100e54790d6d88340893e61f930cbf8b9e
4
- data.tar.gz: 7e89b7bf2d3aaa45cc5b07deab36f5334a61cac44c0aec06206ddbd6eb0ebc22
3
+ metadata.gz: 44da5dd6eb7dee7e08319f7405e97f81e4223f8c88d48ba4a0512fa006f89e78
4
+ data.tar.gz: fe3f5ca8a39b85b1aa4be77a819e910691223cf36e80c6ab337ff1b224a26e16
5
5
  SHA512:
6
- metadata.gz: 944b64f713ad584b56fe386dc63aa6afc0538e498cff4fb46aec9098306b7e436a3d29cebd968157f34e62c9b1b0ce932e15967b4a631f9f04c60ca43d77f4c8
7
- data.tar.gz: 5000ffc97bc381cb94999478c1fe90202b681d5cf87d697f4700cc60b94a7417fd67ca3f5428c4b50acb195bde7850a3a5d809e32c5baaf08ae3a58a2101624a
6
+ metadata.gz: e6648e41c7ff99915716702651cd43fb7fffcff24528a9fb2d7e4a7913303d85d25c3b3f8ef54cc1b716a273836bc3c7fb2911750e1d99f216b2074b03f13ae8
7
+ data.tar.gz: '063048f09b76b10d4f38beb5fcf390d972f0952ed4df7b1053e8078da2bad005b816e21271026b95f8eaef12b8e3e1ce0a4cecf2cf40f965e852a8e2e9854aac'
@@ -1,16 +1,87 @@
1
1
  # Changelog
2
2
 
3
- ## [v1.0.2](https://github.com/bensheldon/good_job/tree/v1.0.2) (2020-07-24)
3
+ ## [v1.1.3](https://github.com/bensheldon/good_job/tree/v1.1.3) (2020-08-14)
4
4
 
5
- [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.0.1...v1.0.2)
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.1.2...v1.1.3)
6
6
 
7
7
  **Fixed bugs:**
8
8
 
9
- - Fix counting of available execution threads [\#58](https://github.com/bensheldon/good_job/pull/58) ([bensheldon](https://github.com/bensheldon))
9
+ - Job exceptions not properly attached to good\_jobs record [\#72](https://github.com/bensheldon/good_job/issues/72)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Capture errors via instrumentation from retry\_on and discard\_on [\#79](https://github.com/bensheldon/good_job/pull/79) ([bensheldon](https://github.com/bensheldon))
14
+ - Document GoodJob::Scheduler with Yard [\#78](https://github.com/bensheldon/good_job/pull/78) ([bensheldon](https://github.com/bensheldon))
15
+
16
+ ## [v1.1.2](https://github.com/bensheldon/good_job/tree/v1.1.2) (2020-08-13)
17
+
18
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.1.1...v1.1.2)
19
+
20
+ **Implemented enhancements:**
21
+
22
+ - Allow the omission of queue names within a scheduler [\#73](https://github.com/bensheldon/good_job/issues/73)
23
+
24
+ **Merged pull requests:**
25
+
26
+ - Allow named queues to be excluded with a minus [\#77](https://github.com/bensheldon/good_job/pull/77) ([bensheldon](https://github.com/bensheldon))
27
+
28
+ ## [v1.1.1](https://github.com/bensheldon/good_job/tree/v1.1.1) (2020-08-12)
29
+
30
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.1.0...v1.1.1)
31
+
32
+ **Implemented enhancements:**
33
+
34
+ - Allow multiple schedulers within the same process. e.g. `queues=mice:2,elephants:4` [\#45](https://github.com/bensheldon/good_job/issues/45)
35
+
36
+ **Merged pull requests:**
37
+
38
+ - Allow instantiation of multiple schedulers via --queues [\#76](https://github.com/bensheldon/good_job/pull/76) ([bensheldon](https://github.com/bensheldon))
39
+ - Extract options parsing to Configuration object [\#74](https://github.com/bensheldon/good_job/pull/74) ([bensheldon](https://github.com/bensheldon))
40
+
41
+ ## [v1.1.0](https://github.com/bensheldon/good_job/tree/v1.1.0) (2020-08-10)
42
+
43
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.0.3...v1.1.0)
10
44
 
11
45
  **Closed issues:**
12
46
 
13
- - repeating/recurring jobs [\#53](https://github.com/bensheldon/good_job/issues/53)
47
+ - Document reliability guarantees [\#59](https://github.com/bensheldon/good_job/issues/59)
48
+ - Document how to hook in exception monitor \(Sentry, Rollbar, etc\) [\#47](https://github.com/bensheldon/good_job/issues/47)
49
+ - Allow an Async mode [\#27](https://github.com/bensheldon/good_job/issues/27)
50
+
51
+ **Merged pull requests:**
52
+
53
+ - Add a callable hook on thread errors [\#71](https://github.com/bensheldon/good_job/pull/71) ([bensheldon](https://github.com/bensheldon))
54
+ - Clarify reliability guarantees [\#70](https://github.com/bensheldon/good_job/pull/70) ([bensheldon](https://github.com/bensheldon))
55
+ - Clean up Readme formatting; re-arrange tests for clarity and values [\#69](https://github.com/bensheldon/good_job/pull/69) ([bensheldon](https://github.com/bensheldon))
56
+ - Create an Async execution mode [\#68](https://github.com/bensheldon/good_job/pull/68) ([bensheldon](https://github.com/bensheldon))
57
+ - Move all stdout to LogSubscriber [\#67](https://github.com/bensheldon/good_job/pull/67) ([bensheldon](https://github.com/bensheldon))
58
+ - Allow schedulers to be restarted; separate unit tests from integration tests [\#66](https://github.com/bensheldon/good_job/pull/66) ([bensheldon](https://github.com/bensheldon))
59
+
60
+ ## [v1.0.3](https://github.com/bensheldon/good_job/tree/v1.0.3) (2020-07-26)
61
+
62
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.0.2...v1.0.3)
63
+
64
+ **Fixed bugs:**
65
+
66
+ - Preserve GoodJob::Jobs when a StandardError is raised [\#60](https://github.com/bensheldon/good_job/issues/60)
67
+
68
+ **Closed issues:**
69
+
70
+ - Have an initial setup generator [\#6](https://github.com/bensheldon/good_job/issues/6)
71
+
72
+ **Merged pull requests:**
73
+
74
+ - Re-perform a job if a StandardError bubbles up; better document job reliability [\#62](https://github.com/bensheldon/good_job/pull/62) ([bensheldon](https://github.com/bensheldon))
75
+ - Update the setup documentation to use correct bin setup command [\#61](https://github.com/bensheldon/good_job/pull/61) ([jm96441n](https://github.com/jm96441n))
76
+ - Allow preservation of finished job records [\#46](https://github.com/bensheldon/good_job/pull/46) ([bensheldon](https://github.com/bensheldon))
77
+
78
+ ## [v1.0.2](https://github.com/bensheldon/good_job/tree/v1.0.2) (2020-07-25)
79
+
80
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.0.1...v1.0.2)
81
+
82
+ **Fixed bugs:**
83
+
84
+ - Fix counting of available execution threads [\#58](https://github.com/bensheldon/good_job/pull/58) ([bensheldon](https://github.com/bensheldon))
14
85
 
15
86
  **Merged pull requests:**
16
87
 
@@ -33,10 +104,6 @@
33
104
 
34
105
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v0.8.2...v0.9.0)
35
106
 
36
- **Merged pull requests:**
37
-
38
- - Allow preservation of finished job records [\#46](https://github.com/bensheldon/good_job/pull/46) ([bensheldon](https://github.com/bensheldon))
39
-
40
107
  ## [v0.8.2](https://github.com/bensheldon/good_job/tree/v0.8.2) (2020-07-18)
41
108
 
42
109
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v0.8.1...v0.8.2)
data/README.md CHANGED
@@ -27,7 +27,8 @@ $ bundle install
27
27
  ## Usage
28
28
 
29
29
  1. Create a database migration:
30
- ```bash
30
+
31
+ ```bash
31
32
  $ bin/rails g good_job:install
32
33
  ```
33
34
 
@@ -38,7 +39,8 @@ $ bundle install
38
39
  ```
39
40
 
40
41
  1. Configure the ActiveJob adapter:
41
- ```ruby
42
+
43
+ ```ruby
42
44
  # config/application.rb
43
45
  config.active_job.queue_adapter = :good_job
44
46
  ```
@@ -57,48 +59,190 @@ $ bundle install
57
59
  ```
58
60
 
59
61
  1. Queue your job 🎉:
62
+
60
63
  ```ruby
61
64
  YourJob.set(queue: :some_queue, wait: 5.minutes, priority: 10).perform_later
62
65
  ```
63
66
 
64
67
  1. In production, the scheduler is designed to run in its own process:
68
+
65
69
  ```bash
66
70
  $ bundle exec good_job
67
71
  ```
68
72
 
69
73
  Configuration options available with `help`:
70
- ```bash
71
- $ bundle exec good_job help start
74
+
75
+ ```bash
76
+ $ bundle exec good_job help start
72
77
 
73
- # Usage:
74
- # good_job start
75
- #
76
- # Options:
77
- # [--max-threads=N] # Maximum number of threads to use for working jobs (default: ActiveRecord::Base.connection_pool.size)
78
- # [--queues=queue1,queue2] # Queues to work from. Separate multiple queues with commas (default: *)
79
- # [--poll-interval=N] # Interval between polls for available jobs in seconds (default: 1)
80
- ```
78
+ Usage:
79
+ good_job start
80
+
81
+ Options:
82
+ [--max-threads=N] # Maximum number of threads to use for working jobs (default: ActiveRecord::Base.connection_pool.size)
83
+ [--queues=queue1,queue2(;queue3,queue4:5;-queue1,queue2)] # Queues to work from. Separate multiple queues with commas; exclude queues with a leading minus; separate isolated execution pools with semicolons and threads with colons (default: *)
84
+ [--poll-interval=N] # Interval between polls for available jobs in seconds (default: 1)
85
+
86
+ Start job worker
87
+ ```
81
88
 
82
- ### Taking advantage of ActiveJob
89
+ 1. Optimize execution to reduce congestion and execution latency.
90
+
91
+ By default, GoodJob creates a single thread execution pool that will execute jobs from any queue. Depending on your application's workload, job types, and service level objectives, you may wish to optimize execution resources; for example, providing dedicated execution resources for transactional emails so they are not delayed by long-running batch jobs. Some options:
92
+
93
+ - Multiple execution pools within a single process:
94
+
95
+ ```bash
96
+ $ bundle exec good_job --queues=transactional_messages:2;batch_processing:1;-transactional_messages,batch_processing:2;* --max-threads=5
97
+ ```
98
+
99
+ This configuration will result in a single process with 4 isolated thread execution pools. Isolated execution pools are separated with a semicolon (`;`) and queue names and thread counts with a colon (`:`)
100
+
101
+ - `transactional_messages:2`: execute jobs enqueued on `transactional_messages` with up to 2 threads.
102
+ - `batch_processing:1` execute jobs enqueued on `batch_processing` with a single thread.
103
+ - `-transactional_messages,batch_processing`: execute jobs enqueued on _any_ queue _excluding_ `transactional_messages` or `batch_processing` with up to 2 threads.
104
+ - `*`: execute jobs on any queue on up to 5 threads, as configured by `--max-threads=5`
105
+
106
+ For moderate workloads, multiple isolated thread execution pools offers a good balance between congestion management and economy.
107
+
108
+ Configuration can be injected by environment variables too:
109
+
110
+ ```bash
111
+ $ GOOD_JOB_QUEUES="transactional_messages:2;batch_processing:1;-transactional_messages,batch_processing:2;*" GOOD_JOB_MAX_THREADS=5 bundle exec good_job
112
+ ```
113
+
114
+ - Multiple processes; for example, on Heroku:
115
+
116
+ ```procfile
117
+ # Procfile
118
+
119
+ # Separate dyno types
120
+ worker: bundle exec good_job --max-threads=5
121
+ transactional_worker: bundle exec good_job --queues=transactional_messages --max-threads=2
122
+ batch_worker: bundle exec good_job --queues=batch_processing --max-threads=1
123
+
124
+ # Combined multi-process dyno
125
+ combined_worker: bundle exec good_job --max-threads=5 & bundle exec good_job --queues=transactional_messages --max-threads=2 & bundle exec good_job --queues=batch_processing --max-threads=1 & wait -n
126
+ ```
127
+
128
+ Running multiple processes can optimize for CPU performance at the expense of greater memory and system resource usage.
83
129
 
84
- ActiveJob has a rich set of built-in functionality for timeouts, error handling, and retrying. For example:
130
+ _Keep in mind, queue operations and management is an advanced discipline. This stuff is complex, especially for heavy workloads and unique processing requirements. Good job 👍_
131
+
132
+ ### Error handling, retries, and reliability
133
+
134
+ GoodJob guarantees that a completely-performed job will run once and only once. GoodJob fully supports ActiveJob's built-in functionality for error handling, retries and timeouts. Writing reliable, transactional, and idempotent `ActiveJob#perform` methods is outside the scope of GoodJob.
135
+
136
+ #### Error handling
137
+
138
+ By default, if a job raises an error while it is being performed, _and it bubbles up to the GoodJob backend_, GoodJob will be immediately re-perform the job until it finishes successfully.
139
+
140
+ - `Exception`-type errors, such as a SIGINT, will always cause a job to be re-performed.
141
+ - `StandardError`-type errors, by default, will cause a job to be re-performed, though this is configurable:
142
+
143
+ ```ruby
144
+ # config/initializers/good_job.rb
145
+ GoodJob.reperform_jobs_on_standard_error = true # => default
146
+ ```
147
+
148
+ To report errors that _do_ bubble up to the GoodJob backend, assign a callable to `GoodJob.on_thread_error`. For example:
149
+
150
+ ```ruby
151
+ # config/initializers/good_job.rb
152
+
153
+ # With Sentry (or Bugsnag, Airbrake, Honeybadger, etc.)
154
+ GoodJob.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
155
+ ```
156
+
157
+ ### Retrying jobs
158
+
159
+ ActiveJob can be configured to retry an infinite number of times, with an exponential backoff. Using ActiveJob's `retry_on` will ensure that errors do not bubble up to the GoodJob backend:
160
+
161
+ ```ruby
162
+ class ApplicationJob < ActiveJob::Base
163
+ retry_on StandardError, wait: :exponentially_longer, attempts: Float::INFINITY
164
+ # ...
165
+ end
166
+ ```
167
+
168
+ When specifying a limited number of retries, care must be taken to ensure that an error does not bubble up to the GoodJob backend because that will result in the job being re-performed:
169
+
170
+ ```ruby
171
+ class ApplicationJob < ActiveJob::Base
172
+ retry_on StandardError, attempts: 5 do |_job, _exception|
173
+ # Log error, etc.
174
+ # You must implement this block, otherwise,
175
+ # Active Job will re-raise the error.
176
+ # Do not re-raise the error, otherwise
177
+ # GoodJob will immediately re-perform the job.
178
+ end
179
+ # ...
180
+ end
181
+ ```
182
+
183
+ GoodJob can be configured to allow omitting `retry_on`'s block argument and implicitly discard un-handled errors:
184
+
185
+ ```ruby
186
+ # config/initializers/good_job.rb
187
+
188
+ # Do NOT re-perform a job if a StandardError bubbles up to the GoodJob backend
189
+ GoodJob.reperform_jobs_on_standard_error = false
190
+ ```
191
+
192
+ When using an exception monitoring service (e.g. Sentry, Bugsnag, Airbrake, Honeybadger, etc), the use of `rescue_on` may be incompatible with their ActiveJob integration. It's safest to explicitly wrap jobs with an exception reporter. For example:
85
193
 
86
194
  ```ruby
87
195
  class ApplicationJob < ActiveJob::Base
88
- # Retry errors an infinite number of times with exponential back-off
89
196
  retry_on StandardError, wait: :exponentially_longer, attempts: Float::INFINITY
197
+
198
+ around_perform do |_job, block|
199
+ block.call
200
+ rescue StandardError => e
201
+ Raven.capture_exception(e)
202
+ raise
203
+ end
204
+ # ...
205
+ end
206
+ ```
207
+
208
+
209
+ ActiveJob's `discard_on` functionality is supported too.
210
+
211
+ #### ActionMailer retries
212
+
213
+ Using a Mailer's `#deliver_later` will enqueue an instance of `ActionMailer::DeliveryJob` which inherits from `ActiveJob::Base` rather than your applications `ApplicationJob`. You can use an initializer to configure retries on `ActionMailer::DeliveryJob`:
214
+
215
+ ```ruby
216
+ # config/initializers/good_job.rb
217
+ ActionMailer::DeliveryJob.retry_on StandardError, wait: :exponentially_longer, attempts: Float::INFINITY
218
+
219
+ # With Sentry (or Bugsnag, Airbrake, Honeybadger, etc.)
220
+ ActionMailer::DeliveryJob.around_perform do |_job, block|
221
+ block.call
222
+ rescue StandardError => e
223
+ Raven.capture_exception(e)
224
+ raise
225
+ end
226
+ ```
90
227
 
91
- # Timeout jobs after 10 minutes
228
+ #### Timeouts
229
+
230
+ Job timeouts can be configured with an `around_perform`:
231
+
232
+ ```ruby
233
+ class ApplicationJob < ActiveJob::Base
92
234
  JobTimeoutError = Class.new(StandardError)
235
+
93
236
  around_perform do |_job, block|
237
+ # Timeout jobs after 10 minutes
94
238
  Timeout.timeout(10.minutes, JobTimeoutError) do
95
239
  block.call
96
240
  end
97
241
  end
98
242
  end
99
243
  ```
100
-
101
- ### Configuring Job Execution Threads
244
+
245
+ ### Configuring job execution threads
102
246
 
103
247
  GoodJob executes enqueued jobs using threads. There is a lot than can be said about [multithreaded behavior in Ruby on Rails](https://guides.rubyonrails.org/threading_and_code_execution.html), but briefly:
104
248
 
@@ -109,6 +253,51 @@ GoodJob executes enqueued jobs using threads. There is a lot than can be said ab
109
253
  3. `$ RAILS_MAX_THREADS=4 bundle exec good_job`
110
254
  4. Implicitly via Rails's database connection pool size (`ActiveRecord::Base.connection_pool.size`)
111
255
 
256
+ ### Executing jobs async / in-process
257
+
258
+ GoodJob is able to run "async" in the same process as the webserver (e.g. `bin/rail s`). GoodJob's async execution mode offers benefits of economy by not requiring a separate job worker process, but with the tradeoff of increased complexity. Async mode can be configured in two ways:
259
+
260
+ - Directly configure the ActiveJob adapter:
261
+
262
+ ```ruby
263
+ # config/environments/production.rb
264
+ config.active_job.queue_adapter = GoodJob::Adapter.new(execution_mode: :async, max_threads: 4, poll_interval: 30)
265
+ ```
266
+ - Or, when using `...queue_adapter = :good_job`, via environment variables:
267
+
268
+ ```bash
269
+ $ GOOD_JOB_EXECUTION_MODE=async GOOD_JOB_MAX_THREADS=4 GOOD_JOB_POLL_INTERVAL=30 bin/rails server
270
+ ```
271
+
272
+ Depending on your application configuration, you may need to take additional steps:
273
+
274
+ - Ensure that you have enough database connections for both web and job execution threads:
275
+
276
+ ```yaml
277
+ # config/database.yml
278
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + ENV.fetch("GOOD_JOB_MAX_THREADS", 4).to_i %>
279
+ ```
280
+
281
+ - When running Puma with workers (`WEB_CONCURRENCY > 0`) or another process-forking webserver, GoodJob's threadpool schedulers should be stopped before forking, restarted after fork, and cleanly shut down on exit. Stopping GoodJob's scheduler pre-fork is recommended to ensure that GoodJob does not continue executing jobs in the parent/controller process. For example, with Puma:
282
+
283
+ ```ruby
284
+ # config/puma.rb
285
+
286
+ before_fork do
287
+ GoodJob::Scheduler.instances.each { |s| s.shutdown }
288
+ end
289
+
290
+ on_worker_boot do
291
+ GoodJob::Scheduler.instances.each { |s| s.restart }
292
+ end
293
+
294
+ on_worker_shutdown do
295
+ GoodJob::Scheduler.instances.each { |s| s.shutdown }
296
+ end
297
+ ```
298
+
299
+ GoodJob is compatible with Puma's `preload_app!` method.
300
+
112
301
  ### Migrating to GoodJob from a different ActiveJob backend
113
302
 
114
303
  If your application is already using an ActiveJob backend, you will need to install GoodJob to enqueue and perform newly created jobs _and_ finish performing pre-existing jobs on the previous backend.
@@ -124,7 +313,8 @@ If your application is already using an ActiveJob backend, you will need to inst
124
313
  ```
125
314
 
126
315
  1. Continue running executors for both backends. For example, on Heroku it's possible to run [two processes](https://help.heroku.com/CTFS2TJK/how-do-i-run-multiple-processes-on-a-dyno) within the same dyno:
127
- ```procfile
316
+
317
+ ```procfile
128
318
  # Procfile
129
319
  # ...
130
320
  worker: bundle exec que ./config/environment.rb & bundle exec good_job & wait -n
@@ -150,15 +340,24 @@ It is also necessary to delete these preserved jobs from the database after a ce
150
340
  - For example, in a Rake task:
151
341
 
152
342
  ```ruby
153
- # GoodJob::Job.finished(1.day.ago).delete_all
343
+ GoodJob::Job.finished(1.day.ago).delete_all
154
344
  ```
345
+
155
346
  - For example, using the `good_job` command-line utility:
156
347
 
157
348
  ```bash
158
349
  $ bundle exec good_job cleanup_preserved_jobs --before-seconds-ago=86400
159
350
  ```
160
351
 
161
- ## Development
352
+ ## Contributing
353
+
354
+ Contributions are welcomed and appreciated 🙏
355
+
356
+ - Review the [Prioritized Project Backlog](https://github.com/bensheldon/good_job/projects/1).
357
+ - Open a new Issue or contribute to an [existing Issue](https://github.com/bensheldon/good_job/issues). Questions or suggestions are fantastic.
358
+ - Participate according to our [Code of Conduct](https://github.com/bensheldon/good_job/projects/1).
359
+
360
+ ### Gem development
162
361
 
163
362
  To run tests:
164
363
 
@@ -167,7 +366,7 @@ To run tests:
167
366
  $ git clone git@github.com:bensheldon/good_job.git
168
367
 
169
368
  # Set up the local environment
170
- $ bin/setup_test
369
+ $ bin/setup
171
370
 
172
371
  # Run the tests
173
372
  $ bin/rspec
@@ -181,7 +380,6 @@ $ bundle exec appraisal
181
380
 
182
381
  # Run tests
183
382
  $ bundle exec appraisal bin/rspec
184
-
185
383
  ```
186
384
 
187
385
  For developing locally within another Ruby on Rails project:
@@ -196,24 +394,23 @@ $ bundle install
196
394
  # => Using good_job 0.1.0 from https://github.com/bensheldon/good_job.git (at /Users/You/Projects/good_job@dc57fb0)
197
395
  ```
198
396
 
199
- ## Releasing
397
+ ### Releasing
200
398
 
201
- Package maintainers can release this gem with the following [gem-release](https://github.com/svenfuchs/gem-release) command:
399
+ Package maintainers can release this gem by running:
202
400
 
203
401
  ```bash
204
402
  # Sign into rubygems
205
403
  $ gem signin
206
404
 
405
+ # Add a .env file with the following:
406
+ # CHANGELOG_GITHUB_TOKEN= # Github Personal Access Token
407
+
207
408
  # Update version number, changelog, and create git commit:
208
- $ bundle exec rake commit_version[minor] # major,minor,patch
409
+ $ bundle exec rake release[minor] # major,minor,patch
209
410
 
210
411
  # ..and follow subsequent directions.
211
412
  ```
212
413
 
213
- ## Contributing
214
-
215
- Contribution directions go here.
216
-
217
414
  ## License
218
415
 
219
416
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).