dddogdiamond/concurrent_worker

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# ConcurrentWorker
[![Build Status](https://travis-ci.org/dddogdiamond/concurrent_worker.svg?branch=master)](https://travis-ci.org/dddogdiamond/concurrent_worker)
[![Code Climate](https://codeclimate.com/github/dddogdiamond/concurrent_worker/badges/gpa.svg)](https://codeclimate.com/github/dddogdiamond/concurrent_worker)
[![Gem Version](https://badge.fury.io/rb/concurrent_worker.svg)](http://badge.fury.io/rb/concurrent_worker)
[![MIT License](http://img.shields.io/github/license/dddogdiamond/concurrent_worker.svg)](LICENSE.txt)

Ruby concurrent worker in thread/process with preparation mechanism.

## Installation

Add this line to your application's Gemfile.

```ruby
gem 'concurrent_worker'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install concurrent_worker

## Usage

### Worker
A worker has a work block wchich will be executed in other thread. You can define a worker with a work block and send requests to the worker with 'req' method.

```ruby
require 'concurrent_worker'
Thread.abort_on_exception = true

# define a work block.
logger = ConcurrentWorker::Worker.new do |*args|
  printf(*args)
  $stdout.flush
  nil
end

...
# call work block asynchronously with 'req' method.
logger.req("thread%d n=%d\n",0, 1)

logger.join
```

If you need some preparation for the work block, you can define 'base block'.

```ruby
logger = ConcurrentWorker::Worker.new do |*args|
  # work block and base block can share object with instance variable(@xxx).
  printf(@file, *args)
  @file.flush
  nil
end

# define base block for some preparation of work block.
logger.set_block(:base_block) do
  open("log.txt", "w") do |file|
    @file = file
    # 'yield_loop_block' must be called in base block.
    # work block will be called in this call.
    yield_loop_block 
  end
end
...
```

The work block and base block are executed in a same thread, and in a worker's instance scope so that they can share object by the worker's instance variable.

### WorkerPool
You can exec work block in some process concurrently.

```ruby
#define a pool of 8 workers with same work block, executed in other process.
wp = ConcurrentWorker::WorkerPool.new(type: :process, pool_max: 8) do |n|
  [n, n.times.inject(:+)]
end

# you can receive the result of work block with callback block.
wp.add_callback do |n, result|
  logger.req("n=%d,result=%d", n, result)
end

(10000000..10000200).each do |n|
  wp.req(n)
end

wp.join
```

Worker uses `Marshal::dump/load` to transport ruby object to other process. So, request arguments and result objects must be able to be Marshal dumped. 


## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at [https://github.com/dddogdiamond/concurrent_worker](https://github.com/dddogdiamond/concurrent_worker).

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).