jobly 0.1.2 → 0.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: c291317ad0589ae8edc781249eed56684185e31e7b376a71c426ca31cade67f9
4
- data.tar.gz: 5bf18f622297cc8446e7e5c3ec3fcc28584cc41a5d80f611fde5e339f44f09ed
3
+ metadata.gz: 2e477c569a3ff769ded464f2d52e4775b254b348464057de68d3a63f2eec053c
4
+ data.tar.gz: 4bfdc207e0b541a52eb7e363cce13ed54635ed0b63e15e61ac5f2b17959ec98d
5
5
  SHA512:
6
- metadata.gz: db20fe73b659b6a90234537a5058d908ed857e1c1b11092afae45d60bb9bfc4565c8d865a104f54c931518197c6fb834d65fe0c1f36734b3e77ffb6daee81ac0
7
- data.tar.gz: 96757bbd1e809d05d6a752cce7bfc4a9c0967d83a78ef913f1ed9c807575dc6c415c31d2a7c6ce4adc629c7aade641bbcb088ff5e5c00b130b5df26c964aba19
6
+ metadata.gz: 1a427c799068ede5b6a1b97b92f22d14cbc6569cd373d06168058e75f7b91a7cc3bb54e9a91774327ca557bef6c9de54af9e0f28bb7359db514ff7ef1f0bcad3
7
+ data.tar.gz: deacef64bbfa47d091134103d7450701a5dcdda4e9f5c21175c05969d17b9370552abc7f8e930a00d2271fc79669752e7aec0a5781d1c0e58cb59060b6fd6f82
data/README.md CHANGED
@@ -15,20 +15,34 @@ Compact job server with API, CLI, Web UI and a Sidekiq heart.
15
15
 
16
16
  ---
17
17
 
18
+ <table><tr>
19
+ <td width='50%'><a target='_screenshot' href='/demo/terminal.gif'><img src='/demo/terminal.gif'/></a></td>
20
+ <td width='50%'><a target='_screenshot' href='/demo/screen.gif'><img src='/demo/screen.gif'/></a></td>
21
+ </tr></table>
22
+
23
+ ---
24
+
18
25
  * [Installation](#installation)
19
26
  * [What's in the Box](#whats-in-the-box)
20
27
  * [Quick Start](#quick-start)
21
28
  * [Usage](#usage)
22
- * [Server](#server)
23
- * [Worker](#worker)
24
- * [Running jobs from the command line](#running-jobs-from-the-command-line)
25
- * [Running jobs through the API](#running-jobs-through-the-api)
29
+ * [Server](#server)
30
+ * [Worker](#worker)
31
+ * [Running jobs from the command line](#running-jobs-from-the-command-line)
32
+ * [Running jobs through the API](#running-jobs-through-the-api)
26
33
  * [Building Jobs](#building-jobs)
34
+ * [The Job Class](#the-job-class)
35
+ * [Job Options](#job-options)
36
+ * [Before, After, On Failure and On Success](#before-after-on-failure-and-on-success)
27
37
  * [Loading Additional Code](#loading-additional-code)
28
38
  * [Configuration](#configuration)
39
+ * [Worker Configuration](#worker-configuration)
29
40
 
30
41
  ---
31
42
 
43
+ Follow development progress:
44
+ [![Waffle.io - Columns and their card count](https://badge.waffle.io/DannyBen/jobly.svg?columns=all&style=flat-square)](https://waffle.io/DannyBen/jobly)
45
+
32
46
  Installation
33
47
  --------------------------------------------------
34
48
 
@@ -126,8 +140,11 @@ subfolder inside it. All your job classes go in this folder (configurable).
126
140
 
127
141
  All job classes will be loaded by any of Jobly's commands.
128
142
 
143
+
144
+ ### The Job Class
145
+
129
146
  A job class is a simple Ruby class inheriting from
130
- `[Jobly::Job](/lib/jobly/job.rb)`.
147
+ [`Jobly::Job`](/lib/jobly/job.rb).
131
148
 
132
149
  The only requirement is that your class implements an `execute` method that
133
150
  optionally accepts keyword arguments (recommended), or a hash.
@@ -144,12 +161,71 @@ end
144
161
  ```
145
162
 
146
163
  Note that these classes are simply Jobly-flavored sidekiq jobs, with these
147
- differences:
164
+ key differences:
148
165
 
149
166
  - You need to implement `execute` instead of `perform`
150
167
  - Job arguments are defined as keyword arguments, instead of positional
151
168
  arguments.
152
169
 
170
+ #### Job Options
171
+
172
+ The `Jobly::Job` class supports these options:
173
+
174
+ | Key | Default | Purpose
175
+ |-------------|-----------|---------------
176
+ | `queue` | `default` | set the name of the queue for this job.
177
+ | `retries` | `5` | number of times to retry on failure.
178
+ | `backtrace` | `5` | number of backtrace lines to show in case of failures. Can be `true`, `false` or a number of lines to save.
179
+
180
+ For example:
181
+
182
+ ```ruby
183
+ class Deploy < Jobly::Job
184
+ queue 'critical'
185
+ backtrace 10
186
+ retries 3
187
+
188
+ def execute
189
+ puts "Deploying"
190
+ end
191
+ end
192
+ ```
193
+
194
+
195
+ #### Before, After, On Failure and On Success
196
+
197
+ The `Jobly::Job` class supports these callback methods:
198
+
199
+ | Method | Description
200
+ |--------------|-------------
201
+ | `before` | Executes before the job starts
202
+ | `on_success` | Executes after the job finishes, and only if it succeeds
203
+ | `on_failure` | Executes after the job finishes, and only if it fails
204
+ | `after` | Executes after the job finishes, regardless of success or failure
205
+
206
+ Each callback method can either be a block or a symbol that points to a local
207
+ method. WHen using a block, you will have the `params` variable available, with
208
+ all the parameteres sent to the job.
209
+
210
+ For example:
211
+
212
+ ```ruby
213
+ class Greet < Jobly::Job
214
+ before do
215
+ logger.info "Starting with #{params[:message]}"
216
+ end
217
+
218
+ after :reboot_computer
219
+
220
+ def execute(message: "Hello")
221
+ puts message
222
+ end
223
+
224
+ def reboot_computer
225
+ system "reboot"
226
+ end
227
+ end
228
+ ```
153
229
 
154
230
 
155
231
  Loading Additional Code
@@ -173,3 +249,19 @@ Configuring Jobly can be done by one of two methods:
173
249
  See this [example config file](/examples/02-full/config/jobly.rb) for a full
174
250
  annotated configuration example and a list of options with their respective
175
251
  environment variables.
252
+
253
+
254
+ ### Worker Configuration
255
+
256
+ For advanced configuration of the sidekiq worker, beyond what the
257
+ `jobly worker` command provides, you can place YAML files in the config
258
+ folder and point the workers to their config file with
259
+ `jobly worker --config name`.
260
+
261
+ These files are simply [sidekiq configuration files][1].
262
+
263
+ See the [worker-config](/examples/06-worker-config) example for more
264
+ information.
265
+
266
+
267
+ [1]: https://github.com/mperham/sidekiq/wiki/Advanced-Options
@@ -2,6 +2,7 @@ require 'requires'
2
2
  require 'byebug' if ENV['BYEBUG']
3
3
 
4
4
  requires 'jobly/refinements'
5
+ requires 'jobly/job_extensions'
5
6
  require 'jobly/exceptions'
6
7
  require 'jobly/sidekiq'
7
8
  require 'jobly/module_functions'
@@ -2,18 +2,40 @@ module Jobly
2
2
  module Commands
3
3
  class WorkerCmd < Base
4
4
  summary "Start a job worker"
5
- usage "jobly worker [--concurrency COUNT]"
5
+ usage "jobly worker [-c COUNT -C PATH (-q NAME)...]"
6
6
  usage "jobly worker (-h|--help)"
7
7
  option "-c, --concurrency COUNT", "Number of parallel jobs [default: 4]"
8
+ option "-C, --config PATH", "Specify a path to a YAML config file. The provided path should be relative to the global config_path directory and without the yml extension"
9
+ option "-q, --queue NAME[,WEIGHT]", "Specify one or more queues that this worker should handle"
10
+
11
+ example "jobly worker --concurrency 10"
12
+ example "jobly worker -q critical -q default -q low"
13
+ example "jobly worker --config primary"
8
14
 
9
15
  def run
10
- concurrency = args['--concurrency']
11
16
  say "Starting sidekiq"
12
- exec "sidekiq --environment #{Jobly.environment} --concurrency #{concurrency} --require #{boot_file}"
17
+ exec "sidekiq #{options_from_args}"
13
18
  end
14
19
 
15
20
  private
16
21
 
22
+ def options_from_args
23
+ result = []
24
+ result << "--environment #{Jobly.environment}"
25
+ result << "--require \"#{boot_file}\""
26
+ result << "--concurrency #{args['--concurrency']}" if args['--concurrency']
27
+
28
+ if args['--config']
29
+ config_file = "#{Jobly.config_path}/#{args['--config']}.yml"
30
+ raise ArgumentError, "Config not found: #{config_file}" unless File.exist? config_file
31
+ result << "--config \"#{config_file}\""
32
+ end
33
+
34
+ args['--queue'].each { |q| result << "--queue #{q}" }
35
+
36
+ result.join ' '
37
+ end
38
+
17
39
  def boot_file
18
40
  @boot_file ||= File.expand_path '../boot.rb', __dir__
19
41
  end
@@ -2,15 +2,58 @@ module Jobly
2
2
  class Job
3
3
  include Sidekiq::Worker
4
4
  include Sidekiq::Status::Worker
5
- sidekiq_options retry: 5
5
+ include JobExtensions::OptionAccessors
6
+ include JobExtensions::Actions
7
+ using KeywordArgs
6
8
 
9
+ sidekiq_options retry: 5, backtrace: 5
10
+ attr_reader :params
11
+
12
+ class << self
13
+ # Allow inheriting jobs to use `execute_async` instead of
14
+ # `perform_async` for consistency with `execute`
15
+ alias_method :execute_async, :perform_async
16
+
17
+ # Allow calling a job with `JobName.execute` instead of
18
+ # `JobName.new.execute`, for consistency.
19
+ def execute(*args)
20
+ new.execute *args
21
+ end
22
+
23
+ # Allow calling a job with `JobName.perform` instead of
24
+ # `JobName.new.perform`, for consistency.
25
+ def perform(*args)
26
+ new.perform *args
27
+ end
28
+
29
+ end
30
+
31
+ # This is the method sidekiq will call. We capture this call and convert
32
+ # the hash argument which was converted to array on sidekiq's side, back
33
+ # to a hash so we can forward to the job's `execute` method, which may
34
+ # implement keyword args.
7
35
  def perform(params={})
8
- params = params.to_h.transform_keys(&:to_sym)
9
- params.empty? ? execute : execute(params)
36
+ @params = params
37
+ run_actions :before
38
+
39
+ begin
40
+ params.empty? ? execute : execute(params.to_kwargs)
41
+ run_actions :success
42
+
43
+ rescue
44
+ run_actions :failure
45
+ raise
46
+
47
+ ensure
48
+ run_actions :after
49
+
50
+ end
10
51
  end
11
52
 
53
+ # Inheriting classes must implement this method only.
12
54
  def execute(params={})
13
55
  raise NotImplementedError
14
56
  end
57
+
15
58
  end
16
59
  end
@@ -0,0 +1,55 @@
1
+ module Jobly
2
+ module JobExtensions
3
+ module Actions
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def before(sym = nil, &block)
11
+ actions[:before] ||= []
12
+ actions[:before] << (sym || block)
13
+ end
14
+
15
+ def after(sym = nil, &block)
16
+ actions[:after] ||= []
17
+ actions[:after] << (sym || block)
18
+ end
19
+
20
+ def on_success(sym = nil, &block)
21
+ actions[:success] ||= []
22
+ actions[:success] << (sym || block)
23
+ end
24
+
25
+ def on_failure(sym = nil, &block)
26
+ actions[:failure] ||= []
27
+ actions[:failure] << (sym || block)
28
+ end
29
+
30
+ def actions
31
+ @actions ||= {}
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def actions
38
+ self.class.actions
39
+ end
40
+
41
+ def run_actions(list)
42
+ return unless actions[list]
43
+
44
+ actions[list].each do |action|
45
+ if action.is_a? Symbol
46
+ send action
47
+ else
48
+ instance_eval &action
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,29 @@
1
+ module Jobly
2
+ module JobExtensions
3
+ module OptionAccessors
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def options
11
+ sidekiq_options
12
+ end
13
+
14
+ def queue(name)
15
+ options['queue'] = name
16
+ end
17
+
18
+ def retries(count)
19
+ options['retry'] = count
20
+ end
21
+
22
+ def backtrace(count)
23
+ options['backtrace'] = count
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -18,6 +18,8 @@ module Jobly
18
18
 
19
19
  refine String do
20
20
  def convert_to_typed
21
+ return true if ['true', 'yes'].include? self
22
+ return false if ['false', 'no'].include? self
21
23
  Integer self rescue self
22
24
  end
23
25
  end
@@ -0,0 +1,15 @@
1
+ module Jobly
2
+ module KeywordArgs
3
+ refine Hash do
4
+ def to_kwargs
5
+ to_h.transform_keys &:to_sym
6
+ end
7
+ end
8
+
9
+ refine Array do
10
+ def to_kwargs
11
+ to_h.transform_keys &:to_sym
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Jobly
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jobly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-09 00:00:00.000000000 Z
11
+ date: 2019-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mister_bin
@@ -185,10 +185,13 @@ files:
185
185
  - lib/jobly/config.ru
186
186
  - lib/jobly/exceptions.rb
187
187
  - lib/jobly/job.rb
188
+ - lib/jobly/job_extensions/actions.rb
189
+ - lib/jobly/job_extensions/option_accessors.rb
188
190
  - lib/jobly/jobs.rb
189
191
  - lib/jobly/module_functions.rb
190
192
  - lib/jobly/refinements/argument_converters.rb
191
193
  - lib/jobly/refinements/convert_to_typed.rb
194
+ - lib/jobly/refinements/keyword_args.rb
192
195
  - lib/jobly/server.rb
193
196
  - lib/jobly/sidekiq.rb
194
197
  - lib/jobly/version.rb