README.md in gush-0.1.1 vs README.md in gush-0.1.2
- old
+ new
@@ -1,9 +1,14 @@
-# Gush [![Build Status](https://travis-ci.org/pokonski/gush.svg?branch=master)](https://travis-ci.org/pokonski/gush)
+# Gush [![Build Status](https://travis-ci.org/chaps-io/gush.svg?branch=master)](https://travis-ci.org/chaps-io/gush)
+## [![](http://i.imgur.com/ya8Wnyl.png)](https://chaps.io) proudly made by [Chaps](https://chaps.io)
+
Gush is a parallel workflow runner using only Redis as its message broker and Sidekiq for workers.
+## Theory
+
+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.
## Installation
Add this line to your application's Gemfile:
gem 'gush'
@@ -24,13 +29,13 @@
Here is a complete example of a workflow you can create:
```ruby
# workflows/sample_workflow.rb
class SampleWorkflow < Gush::Workflow
- def configure
- run FetchJob1
- run FetchJob2
+ def configure(url_to_fetch_from)
+ run FetchJob1, params: { url: url_to_fetch_from }
+ run FetchJob2, params: {some_flag: true, url: 'http://url.com'}
run PersistJob1, after: FetchJob1
run PersistJob2, after: FetchJob2
run Normalize,
@@ -50,38 +55,81 @@
For the Workflow above, the graph will look like this:
![SampleWorkflow](http://i.imgur.com/SmeRRVT.png)
-### Defining jobs
+#### Passing parameters to jobs
+
+You can pass any primitive arguments into jobs while defining your workflow:
+
+```ruby
+# workflows/sample_workflow.rb
+class SampleWorkflow < Gush::Workflow
+ def configure
+ run FetchJob1, params: { url: "http://some.com/url" }
+ end
+end
+```
+
+See below to learn how to access those params inside your job.
+
+#### Defining jobs
+
Jobs are classes inheriting from `Gush::Job`:
```ruby
-#workflows/sample/fetch_job1.rb
class FetchJob1 < Gush::Job
def work
# do some fetching from remote APIs
+
+ params #=> {url: "http://some.com/url"}
end
end
```
+`params` method is a hash containing your (optional) parameters passed to `run` method in the workflow.
+
+#### Passing arguments to workflows
+
+Workflows can accept any primitive arguments in their constructor, which then will be availabe in your
+`configure` method.
+
+Here's an example of a workflow responsible for publishing a book:
+
+```ruby
+# workflows/sample_workflow.rb
+class PublishBookWorkflow < Gush::Workflow
+ def configure(url, isbn)
+ run FetchBook, params: { url: url }
+ run PublishBook, params: { book_isbn: isbn }
+ end
+end
+```
+
+and then create your workflow with those arguments:
+
+```ruby
+PublishBookWorkflow.new("http://url.com/book.pdf", "978-0470081204")
+```
+
+
### Running workflows
Now that we have defined our workflow we can use it:
#### 1. Initialize and save it
```ruby
-flow = SampleWorkflow.new
+flow = SampleWorkflow.new(optional, arguments)
flow.save # saves workflow and its jobs to Redis
```
**or:** you can also use a shortcut:
```ruby
-flow = SampleWorkflow.create
+flow = SampleWorkflow.create(optional, arguments)
```
#### 2. Start workflow
First you need to start Sidekiq workers:
@@ -97,11 +145,55 @@
```
Now Gush will start processing jobs in background using Sidekiq
in the order defined in `configure` method inside Workflow.
+### Pipelining
+Gush offers a useful feature which lets you pass results of a job to its dependencies, so they can act accordingly.
+
+**Example:**
+
+Let's assume you have two jobs, `DownloadVideo`, `EncodeVideo`.
+The latter needs to know where the first one downloaded the file to be able to open it.
+
+
+```ruby
+class DownloadVideo < Gush::Job
+ def work
+ downloader = VideoDownloader.fetch("http://youtube.com/?v=someytvideo")
+
+ output(downloader.file_path)
+ end
+end
+```
+
+`output` method is Gush's way of saying: "I want to pass this down to my descendants".
+
+Now, since `DownloadVideo` finished and its dependant job `EncodeVideo` started, we can access that payload down the (pipe)line:
+
+```ruby
+class EncodeVideo < Gush::Job
+ def work
+ video_path = payloads["DownloadVideo"]
+ end
+end
+```
+
+`payloads` is a hash containing outputs from all parent jobs, where job class names are the keys.
+
+**Note:** `payloads` will only contain outputs of the job's ancestors. So if job `A` depends on `B` and `C`,
+the `paylods` hash will look like this:
+
+```ruby
+{
+ "B" => (...),
+ "C" => (...)
+}
+```
+
+
### Checking status:
#### In Ruby:
```ruby
@@ -124,23 +216,27 @@
```
bundle gush list
```
+
### Requiring workflows inside your projects
-**Skip this step if using Gush inside Rails application, workflows will already be loaded**
-
When using Gush and its CLI commands you need a Gushfile.rb in root directory.
Gushfile should require all your Workflows and jobs, for example:
```ruby
require_relative './lib/your_project'
Dir[Rails.root.join("app/workflows/**/*.rb")].each do |file|
require file
end
```
+
+## Contributors
+
+- [Mateusz Lenik](https://github.com/mlen)
+- [Michał Krzyżanowski](https://github.com/krzyzak)
## Contributing
1. Fork it ( http://github.com/pokonski/gush/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)