Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kennethkalmer/ruote-kit

RESTish wrapper for ruote workflow engine
https://github.com/kennethkalmer/ruote-kit

Last synced: 3 days ago
JSON representation

RESTish wrapper for ruote workflow engine

Awesome Lists containing this project

README

        

# ruote-kit (ruote on rack)

A wrapper around the [ruote](http://ruote.rubyforge.org) workflow engine,
built as a modular [Sinatra](http://www.sinatrarb.com/) application.

Follow development:

* \#ruote on Freenode
*
*
* [@kennethkalmer](http://twitter.com/kennethkalmer) on Twitter

## Dependencies

ruote-kit uses [Bundler](http://gembundler.com/) to setup and maintain its
environment. Before running ruote-kit for the first time you need to install
Bundler (gem install bundler) and then run:

```bash
$ bundle install
```

Bundler will download all the required gems and install them for you.

Have a look at the Gemfile if you want to see the various dependencies.

## Getting started quickly

### Using the source

* Get the source files using git

```bash
$ git clone http://github.com/kennethkalmer/ruote-kit.git
$ cd ruote-kit
```

* Make sure every dependency is resolved

```bash
$ bundle install
```

* Get going

```bash
$ bundle exec rackup
```

### Using the RubyGem / Bundler

* You'll need an empty directory

```bash
$ mkdir my-ruote-kit
$ cd my-ruote-kit
```

* There are two files needed in that directory: Gemfile and config.ru

* Gemfile

```ruby
source :rubygems
gem 'ruote', :git => 'git://github.com/jmettraux/ruote.git'
gem 'ruote-kit', :git => 'git://github.com/kennethkalmer/ruote-kit.git'
```

* config.ru

see for example

* Install all needed gems

```bash
$ bundle install
```

* Get going

```bash
$ bundle exec rackup
```

### Accessing the web interface

If ruote-kit starts up without any issues (ie missing dependencies), you can
point your browser to to get going.
By default ruote-kit binds to all IP addresses, so this works out the box
remotely too.

## Plugging ruote-kit into your rack-stack

ruote-kit is fully self-sufficient piece of rack, but can be slotted into any
rack middleware stack without issues.

Example:

```ruby
RuoteKit.engine = Ruote::Engine.new(
Ruote::Worker.new(
Ruote::FsStorage.new('ruote_work')))

RuoteKit.engine.register do
catchall
end

# Slot into the stack
use RuoteKit::Application
```

### Notes for Rails

ruote-kit ships with an application template for Ruby on Rails 3.

#### Generate a new Rails app using ruote[-kit]

* install Rails

```bash
$ gem install rails
```

* create a new Rails app by running

```bash
$ rails new foo -m https://github.com/kennethkalmer/ruote-kit/raw/master/rails-template.rb
```

* cd into the new Rails dir

```bash
$ cd foo
```

* make sure all dependencies are met

```bash
$ bundle install
```

#### Update an existing Rails app to use ruote[-kit]

* in your Rails dir, apply the app template

```bash
$ rake rails:template LOCATION=https://github.com/kennethkalmer/ruote-kit/raw/master/rails-template.rb
```

#### Configure your ruote-kit integration

See config/initializers/ruote-kit.rb in your Rails app.

#### Run

```bash
$ rails server
```

Browse to and you'll see there are no running processes. You could change that using the "Launch process" link ;-)

#### Using Ruote from within Rails

You can access Ruote's engine anywhere in your Rails code by calling

```ruby
RuoteKit.engine
```

So launching a workflow process is as easy as

```ruby
RuoteKit.engine.launch(your_process_definition)
```

The storage participant (used by the catchall participant) is available at

```ruby
RuoteKit.storage_participant
```

#### Example application

See for an example Rails app.

## Configuring ruote-kit & ruote

ruote-kit itself needs only little configuration, the only thing to do is to
bind a ruote engine to use. That engine may be configured, see
for details.

When using the source version, you'll have to edit the `config.ru` file if you
want to change the engine configuration. It defaults to use file system
persistence and runs a [worker](http://ruote.rubyforge.org/configuration.html#worker) within the engine.
The persistence files will be stored in a sub directory called `ruote_work_#{ENV}`.

When using the gem version or plugging ruote-kit into your rack stack, you'll
have to bind the ruote engine to use yourself. See the examples above.

### Registration of participants

ruote participants may be registered using the register method of the engine.
It expects a block containing of participant and one or less _catchall_ calls.

```ruby
RuoteKit.engine.register do
participant 'no_op', Ruote::NoOpParticipant
catchall
end
```

This example binds the identifier "no_op" to the `Ruote::NoOpParticipant` implementation.

The catchall is synonymous for

```ruby
participant /.+/, Ruote::StorageParticipant
```

With such a definition and since it comes last, it means that all the workitems that are not for participant "no_op" end up in the storage participant. Thus

```ruby
Ruote.define do
concurrence do
ceo
no_op
cto
end
end
```

will route three concurrent workitems, one for "ceo" and one for "cto" to the storage participant (see the "workitems" tab in your ruote-kit interface) and one to "no_op", the no operation participant (which will reply immediately).

When playing initially with ruote-kit it's probably better to leave the registration block to:

```ruby
RuoteKit.engine.register do
catchall
end
```

So that all the workitems are placed in a storage participant.

If you want to learn more about ruote's participants, have a look at
.

## The _workitems_ resource

The _workitems_ resource relies on the Ruote::StorageParticipant. You'll have to
register at least one Storage Participant if you ever want to see a workitem in
the resource. Example:

```ruby
require 'ruote/part/storage_participant'
RuoteKit.engine.register_participant :storage, Ruote::StorageParticipant
```

You may also use the catchall participant provided by ruote. It's named '.+',
so it will catch all workitems for any participant mentioned in your workflow
definitions which are not already caught by another (previously) registered
participant. So make sure to register the catchall after your own participants.
The catchall participant may be registered by calling _catchall_ within the
block given to Ruote::Engine#register (this will use Ruote::StorageParticipant
as participant implementation, you may use any options of
Ruote::Engine#register_participant to overwrite that default -- see the example
above).

## Running workers

Always make sure to have a running ruote [worker](http://ruote.rubyforge.org/configuration.html#worker) for your storage.
The shipped config.ru takes care of that, but if you use the gem version or use
ruote-kit as part of your rack stack, you'll need to make sure there is a running worker.

Perhaps it's best to give some more explanations about the architecture of ruote
here. Ruote's engine class is shallow, just a few methods that insert launch and
reply orders in the storage and read it when querying for process statuses. You
see: The storage is important, it is used as communications backend between the
various parts of ruote. The engine class and the storage are not enough, though.
The real work is done by one or more workers which query the storage for things
to do.

(note: compared to a flow hardcoded in a set of controllers, ruote is very slow. After all, it "interprets" its flows. When processes are uniquely composed of tiny services (no human participants) ruote will lose any time. When human participants are involved, flows are as slow as the slowest human participants)

Ruote ships with one worker implementation and various storage implementations.
Have a look at for an overview.

In the most examples above, the worker instance is bound to the engine which
is given to RuoteKit.engine:

```ruby
RuoteKit.engine = Ruote::Engine.new(
Ruote::Worker.new(
Ruote::FsStorage.new('ruote_work')))
```

That is fine, especially when there is only one instance of the app running or
the storage implementation supports multiple workers, because if there is more
than one instance of the app running, there will be more than one worker
operating on the same storage.

If you want to use a storage implementation which doesn't support multiple
workers (Ruote::FsStorage under Windows, for example), you should start a
dedicated worker in its own instance. In config.ru (or whereever you configure
the engine to be used by ruote-kit), instanciate the engine without a worker:

```ruby
RuoteKit.engine = Ruote::Engine.new(
Ruote::FsStorage.new('ruote_work'))
```

ruote-kit or your rack app will start with no problems, you may even launch
processes, but they'll never show up under `/_ruote/processes`: There is no
worker which processes the launch requests stored in the storage.

To run a worker you need to setup a worker script similar to the rake task
example below:

```ruby
require 'rake'
require 'ruote-kit'

desc "Run a ruote-kit worker"
task :ruote_kit_worker do

RuoteKit.run_worker(Ruote::FsStorage.new('ruote_work'))
end
```

Make sure to configure the storage in the same way as in the rest of the
application or you won't get what you expect ;-)

If you used the Ruby on Rails 3 template for 'installing' ruote-kit,
a ruote:run_worker task is added automatically (in lib/tasks/ruote.rake).

You also should consider using a separate worker instance when you're running
ruote-kit or your rack app in an environment like Passenger: You won't be sure
the app runs all the time, so it's likely that scheduled events will be missed
(better: triggered too late). If you don't want to start a separate worker
process, configure Passenger in a way that your app won't be killed in a very
long time (Passenger 3 provides an option to ensure one instance of the app
won't be killed) and make sure your storage implementation supports multiple
workers.

## Feedback & bug reports

Feedback and bug reports are welcome on the [mailing-list](http://groups.google.com/group/openwferu-users), or on the `#ruote` IRC channel at Freenode.net.

Please do not hesitate to come back with _any_ feedback.

## License

(The MIT License)

Copyright (c) 2009-2013 Kenneth Kalmer (Internet Exchange CC, Clear Planet Information Solutions Pty Ltd)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

## libraries used

- rack,
- sinatra,
- sinatra-respond_to,
- haml,
- yajl-ruby,
- jquery,

Many thanks to the authors and contributors