gush-mmx 0.4.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2f55fd6914dcc9cf58d63c7bf6df6489c8f9eb76
4
+ data.tar.gz: aa4bcedcb43924b69197c361e5c4964ac42e196d
5
+ SHA512:
6
+ metadata.gz: 51223f508abf7a0e6286bc34f118553d49ecc7e9b49dc9c62e1a5adf7e83ae453a59efd02679d49bfa6d3b01a5bf41a068f0cc79224e5d60d9f1f9aea4677dd5
7
+ data.tar.gz: 200c6e51fe0d8bebc12d7ec8989bd7883392f5ea7e51463ef6acfe2df29df7440d925875980f2e676062d5feb625d313412ec00ef74d9f129a75f59f95d6085c
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ workflows/
18
+ tmp
19
+ test.rb
20
+ /Gushfile.rb
21
+ dump.rdb
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ script: "bundle exec rspec"
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.6
6
+ - 2.2.2
7
+ services:
8
+ - redis-server
9
+ email:
10
+ recipients:
11
+ - piotrek@okonski.org
12
+ on_success: change
13
+ on_failure: always
@@ -0,0 +1,3 @@
1
+ # 0.4
2
+
3
+ - remove hard dependency on Yajl, so Gush can work with non-MRI Rubies ([#31](https://github.com/chaps-io/gush/pull/31) by [Nick Rakochy](https://github.com/chaps-io/gush/pull/31))
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ platforms :mri, :ruby do
5
+ gem 'yajl-ruby'
6
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Chaps sp. z o.o.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,258 @@
1
+ # Gush [![Build Status](https://travis-ci.org/chaps-io/gush.svg?branch=master)](https://travis-ci.org/chaps-io/gush)
2
+
3
+ ## [![](http://i.imgur.com/ya8Wnyl.png)](https://chaps.io) proudly made by [Chaps](https://chaps.io)
4
+
5
+ Gush is a parallel workflow runner using only Redis as its message broker and Sidekiq for workers.
6
+
7
+
8
+ # New
9
+
10
+ Options for config:
11
+ * redis_prefix - Redis namespace
12
+ * sidekiq_queue - queue name in Sidekiq
13
+
14
+
15
+
16
+ ## Theory
17
+
18
+ Gush relies on directed acyclic graphs to store dependencies, see [Parallelizing Operations With Dependencies](https://msdn.microsoft.com/en-us/magazine/dd569760.aspx) by Stephen Toub.
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ gem 'gush'
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install gush
32
+
33
+ ## Usage
34
+
35
+ ### Defining workflows
36
+
37
+ The DSL for defining jobs consists of a single `run` method.
38
+ Here is a complete example of a workflow you can create:
39
+
40
+ ```ruby
41
+ # workflows/sample_workflow.rb
42
+ class SampleWorkflow < Gush::Workflow
43
+ def configure(url_to_fetch_from)
44
+ run FetchJob1, params: { url: url_to_fetch_from }
45
+ run FetchJob2, params: {some_flag: true, url: 'http://url.com'}
46
+
47
+ run PersistJob1, after: FetchJob1
48
+ run PersistJob2, after: FetchJob2
49
+
50
+ run Normalize,
51
+ after: [PersistJob1, PersistJob2],
52
+ before: Index
53
+
54
+ run Index
55
+ end
56
+ end
57
+ ```
58
+
59
+ **Hint:** For debugging purposes you can vizualize the graph using `viz` command:
60
+
61
+ ```
62
+ bundle exec gush viz SampleWorkflow
63
+ ```
64
+
65
+ For the Workflow above, the graph will look like this:
66
+
67
+ ![SampleWorkflow](http://i.imgur.com/SmeRRVT.png)
68
+
69
+
70
+ #### Passing parameters to jobs
71
+
72
+ You can pass any primitive arguments into jobs while defining your workflow:
73
+
74
+ ```ruby
75
+ # app/workflows/sample_workflow.rb
76
+ class SampleWorkflow < Gush::Workflow
77
+ def configure
78
+ run FetchJob1, params: { url: "http://some.com/url" }
79
+ end
80
+ end
81
+ ```
82
+
83
+ See below to learn how to access those params inside your job.
84
+
85
+ #### Defining jobs
86
+
87
+ Jobs are classes inheriting from `Gush::Job`:
88
+
89
+ ```ruby
90
+ # app/jobs/fetch_job.rb
91
+ class FetchJob < Gush::Job
92
+ def work
93
+ # do some fetching from remote APIs
94
+
95
+ params #=> {url: "http://some.com/url"}
96
+ end
97
+ end
98
+ ```
99
+
100
+ `params` method is a hash containing your (optional) parameters passed to `run` method in the workflow.
101
+
102
+ #### Passing arguments to workflows
103
+
104
+ Workflows can accept any primitive arguments in their constructor, which then will be available in your
105
+ `configure` method.
106
+
107
+ Here's an example of a workflow responsible for publishing a book:
108
+
109
+ ```ruby
110
+ # app/workflows/sample_workflow.rb
111
+ class PublishBookWorkflow < Gush::Workflow
112
+ def configure(url, isbn)
113
+ run FetchBook, params: { url: url }
114
+ run PublishBook, params: { book_isbn: isbn }
115
+ end
116
+ end
117
+ ```
118
+
119
+ and then create your workflow with those arguments:
120
+
121
+ ```ruby
122
+ PublishBookWorkflow.new("http://url.com/book.pdf", "978-0470081204")
123
+ ```
124
+
125
+
126
+ ### Running workflows
127
+
128
+ Now that we have defined our workflow we can use it:
129
+
130
+ #### 1. Initialize and save it
131
+
132
+ ```ruby
133
+ flow = SampleWorkflow.new(optional, arguments)
134
+ flow.save # saves workflow and its jobs to Redis
135
+ ```
136
+
137
+ **or:** you can also use a shortcut:
138
+
139
+ ```ruby
140
+ flow = SampleWorkflow.create(optional, arguments)
141
+ ```
142
+
143
+ #### 2. Start workflow
144
+
145
+ First you need to start Sidekiq workers:
146
+
147
+ ```
148
+ bundle exec gush workers
149
+ ```
150
+
151
+ and then start your workflow:
152
+
153
+ ```ruby
154
+ flow.start!
155
+ ```
156
+
157
+ Now Gush will start processing jobs in background using Sidekiq
158
+ in the order defined in `configure` method inside Workflow.
159
+
160
+ ### Pipelining
161
+
162
+ Gush offers a useful feature which lets you pass results of a job to its dependencies, so they can act accordingly.
163
+
164
+ **Example:**
165
+
166
+ Let's assume you have two jobs, `DownloadVideo`, `EncodeVideo`.
167
+ The latter needs to know where the first one downloaded the file to be able to open it.
168
+
169
+
170
+ ```ruby
171
+ class DownloadVideo < Gush::Job
172
+ def work
173
+ downloader = VideoDownloader.fetch("http://youtube.com/?v=someytvideo")
174
+
175
+ output(downloader.file_path)
176
+ end
177
+ end
178
+ ```
179
+
180
+ `output` method is Gush's way of saying: "I want to pass this down to my descendants".
181
+
182
+ Now, since `DownloadVideo` finished and its dependant job `EncodeVideo` started, we can access that payload down the (pipe)line:
183
+
184
+ ```ruby
185
+ class EncodeVideo < Gush::Job
186
+ def work
187
+ video_path = payloads["DownloadVideo"]
188
+ end
189
+ end
190
+ ```
191
+
192
+ `payloads` is a hash containing outputs from all parent jobs, where job class names are the keys.
193
+
194
+ **Note:** `payloads` will only contain outputs of the job's ancestors. So if job `A` depends on `B` and `C`,
195
+ the `payloads` hash will look like this:
196
+
197
+ ```ruby
198
+ {
199
+ "B" => (...),
200
+ "C" => (...)
201
+ }
202
+ ```
203
+
204
+
205
+ ### Checking status:
206
+
207
+ #### In Ruby:
208
+
209
+ ```ruby
210
+ flow.reload
211
+ flow.status
212
+ #=> :running|:finished|:failed
213
+ ```
214
+
215
+ `reload` is needed to see the latest status, since workflows are updated asynchronously.
216
+
217
+ #### Via CLI:
218
+
219
+ - of a specific workflow:
220
+
221
+ ```
222
+ bundle exec gush show <workflow_id>
223
+ ```
224
+
225
+ - of all created workflows:
226
+
227
+ ```
228
+ bundle exec gush list
229
+ ```
230
+
231
+
232
+ ### Requiring workflows inside your projects
233
+
234
+ When using Gush and its CLI commands you need a Gushfile.rb in root directory.
235
+ Gushfile should require all your Workflows and jobs, for example:
236
+
237
+ ```ruby
238
+ require_relative './lib/your_project'
239
+
240
+ Dir[Rails.root.join("app/workflows/**/*.rb")].each do |file|
241
+ require file
242
+ end
243
+ ```
244
+
245
+ ## Contributors
246
+
247
+ - [Mateusz Lenik](https://github.com/mlen)
248
+ - [Michał Krzyżanowski](https://github.com/krzyzak)
249
+ - [Maciej Nowak](https://github.com/keqi)
250
+ - [Maciej Kołek](https://github.com/ferusinfo)
251
+
252
+ ## Contributing
253
+
254
+ 1. Fork it ( http://github.com/chaps-io/gush/fork )
255
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
256
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
257
+ 4. Push to the branch (`git push origin my-new-feature`)
258
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require "pathname"
3
+ require "bundler"
4
+ Bundler.require
5
+
6
+ bin_file = Pathname.new(__FILE__).realpath
7
+ # add self to libpath
8
+ $:.unshift File.expand_path("../../lib", bin_file)
9
+
10
+ require 'gush'
11
+
12
+ begin
13
+ Gush::CLI.start(ARGV)
14
+ rescue Gush::WorkflowNotFound
15
+ puts "Workflow not found".red
16
+ rescue Gush::DependencyLevelTooDeep
17
+ puts "Dependency level too deep. Perhaps you have a dependency cycle?".red
18
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "gush-mmx"
7
+ spec.version = "0.4.2"
8
+ spec.authors = ["Piotrek Okoński", "Max Ivak"]
9
+ spec.email = ["piotrek@okonski.org", "maxivak@gmail.com"]
10
+ spec.summary = "Fast and distributed workflow runner using only Sidekiq and Redis"
11
+ spec.description = "Gush is a parallel workflow runner using only Redis as its message broker and Sidekiq for workers."
12
+ spec.homepage = "https://github.com/pokonski/gush"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = "gush"
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "sidekiq", "~> 4.0"
21
+ spec.add_dependency "multi_json", "~> 1.11"
22
+ spec.add_dependency "redis", "~> 3.2"
23
+ spec.add_dependency "hiredis", "~> 0.6"
24
+ spec.add_dependency "ruby-graphviz", "~> 1.2"
25
+ spec.add_dependency "terminal-table", "~> 1.4"
26
+ spec.add_dependency "colorize", "~> 0.7"
27
+ spec.add_dependency "thor", "~> 0.19"
28
+ spec.add_dependency "launchy", "~> 2.4"
29
+ spec.add_development_dependency "bundler", "~> 1.5"
30
+ spec.add_development_dependency "rake", "~> 10.4"
31
+ spec.add_development_dependency "rspec", '~> 3.0'
32
+ spec.add_development_dependency "pry", '~> 0.10'
33
+ spec.add_development_dependency 'fakeredis', '~> 0.5'
34
+ end
@@ -0,0 +1,61 @@
1
+ require "bundler/setup"
2
+
3
+ require "graphviz"
4
+ require "hiredis"
5
+ require "pathname"
6
+ require "redis"
7
+ require "securerandom"
8
+ require "sidekiq"
9
+ require "multi_json"
10
+
11
+ require "gush/json"
12
+ require "gush/cli"
13
+ require "gush/cli/overview"
14
+ require "gush/graph"
15
+ require "gush/client"
16
+ require "gush/configuration"
17
+ require "gush/errors"
18
+ require "gush/job"
19
+ require "gush/worker"
20
+ require "gush/workflow"
21
+
22
+ module Gush
23
+ def self.gushfile
24
+ configuration.gushfile
25
+ end
26
+
27
+ def self.root
28
+ Pathname.new(__FILE__).parent.parent
29
+ end
30
+
31
+ def self.configuration
32
+ @configuration ||= Configuration.new
33
+ end
34
+
35
+ def self.configure
36
+ yield configuration
37
+ reconfigure_sidekiq
38
+ end
39
+
40
+ def self.reconfigure_sidekiq
41
+ #puts "^^^^^^^^ reconfigure_sidekiq ^^^"
42
+ Sidekiq.configure_server do |config|
43
+ #config.redis = { url: configuration.redis_url, queue: configuration.namespace}
44
+
45
+ opts = { url: configuration.redis_url, namespace: configuration.redis_prefix, queue: configuration.sidekiq_queue }
46
+ #puts "sidekiq server opts: #{opts}"
47
+ config.redis = { url: configuration.redis_url, namespace: configuration.redis_prefix, queue: configuration.sidekiq_queue }
48
+ end
49
+
50
+ Sidekiq.configure_client do |config|
51
+ #config.redis = { url: configuration.redis_url, queue: configuration.namespace}
52
+
53
+ opts = { url: configuration.redis_url, namespace: configuration.redis_prefix, queue: configuration.sidekiq_queue }
54
+ #puts "sidekiq client opts: #{opts}"
55
+
56
+ config.redis = { url: configuration.redis_url, namespace: configuration.redis_prefix, queue: configuration.sidekiq_queue }
57
+ end
58
+ end
59
+ end
60
+
61
+ #Gush.reconfigure_sidekiq