jflow 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +80 -0
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/jflow_worker +42 -0
- data/bin/setup +8 -0
- data/jflow.gemspec +36 -0
- data/lib/jflow.rb +36 -0
- data/lib/jflow/activity.rb +81 -0
- data/lib/jflow/activity_mixin.rb +18 -0
- data/lib/jflow/activity_worker.rb +81 -0
- data/lib/jflow/configuration.rb +12 -0
- data/lib/jflow/version.rb +3 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e8525329c288e5a0027699c40ad1539367224ec2
|
4
|
+
data.tar.gz: 3545904aeda9e29048224b2983e55a805fbaec39
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cdae9e071195443da31a403513674b2cf69378d4b59afde71f5f22d113ed99f9aa9a764d067ebc78a54dd5e5bc7828e4d29a2f8c31d94f091bf54c7c28fac57c
|
7
|
+
data.tar.gz: 0b9d85ff36b13e3bd6bee7568b8a622927ae5b9d0cb87b41e25b956215835a98c11f686051e4fe6650fa1fbf7c503009eeffee701367724bad2d93e6438c2d98
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Jflow
|
2
|
+
|
3
|
+
JFlow is a gem that aims to let you start SWF flow activity workers for JRuby.
|
4
|
+
|
5
|
+
The official framework uses Forking and thus not compatible with the JVM. This aims to give an alternative for Jruby.
|
6
|
+
|
7
|
+
*For now this only works for Activities and not workflows*
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'jflow'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install jflow
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Create an Activity
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
Class FooActivity
|
31
|
+
include JFlow::ActivityMixin
|
32
|
+
|
33
|
+
activity "policy_scan.run" do
|
34
|
+
{
|
35
|
+
domain: "alexandria-development",
|
36
|
+
default_task_list: {
|
37
|
+
name: "xray_activity_tasklist"
|
38
|
+
},
|
39
|
+
version: "1.4",
|
40
|
+
default_task_schedule_to_start_timeout: "600",
|
41
|
+
default_task_schedule_to_close_timeout: "600",
|
42
|
+
default_task_start_to_close_timeout: "600",
|
43
|
+
default_task_heartbeat_timeout: "600"
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
"foo"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
### Launch the workers
|
54
|
+
|
55
|
+
This gem provides you with a binary called jflow_worker. This binary requires a json configuration file.
|
56
|
+
|
57
|
+
```bash
|
58
|
+
jflow_worker -f worker.json
|
59
|
+
```
|
60
|
+
|
61
|
+
Example of a worker.json
|
62
|
+
```json
|
63
|
+
{
|
64
|
+
"domain": "foodomain",
|
65
|
+
"tasklist": "footasklist",
|
66
|
+
"number_of_workers": 100,
|
67
|
+
"activities_path": ["/home/pate/git/foobar/lib/flow/activities"]
|
68
|
+
}
|
69
|
+
```
|
70
|
+
|
71
|
+
## Development
|
72
|
+
|
73
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
74
|
+
|
75
|
+
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).
|
76
|
+
|
77
|
+
## Contributing
|
78
|
+
|
79
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/jflow.
|
80
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/jflow_worker
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "jflow"
|
5
|
+
require "slop"
|
6
|
+
|
7
|
+
opts = Slop.parse do |o|
|
8
|
+
o.string '-f', '--file', 'worker configuration file'
|
9
|
+
end
|
10
|
+
|
11
|
+
configuration = JSON.parse(File.read(opts[:file]))
|
12
|
+
|
13
|
+
configuration_validator = {
|
14
|
+
"number_of_workers" => "integer",
|
15
|
+
"domain" => "string",
|
16
|
+
"tasklist" => "string",
|
17
|
+
"activities_path" => "array"
|
18
|
+
}
|
19
|
+
|
20
|
+
validator = HashValidator.validate(configuration, configuration_validator)
|
21
|
+
raise "configuration is invalid! #{validator.errors}" unless validator.valid?
|
22
|
+
|
23
|
+
JFlow.configure do |c|
|
24
|
+
c.load_paths = configuration["activities_path"]
|
25
|
+
end
|
26
|
+
|
27
|
+
JFlow.load_activities
|
28
|
+
|
29
|
+
threads = []
|
30
|
+
|
31
|
+
configuration["number_of_workers"].times do |i|
|
32
|
+
threads << Thread.new do
|
33
|
+
domain = configuration["domain"]
|
34
|
+
tasklist = configuration["tasklist"]
|
35
|
+
JFlow::ActivityWorker.new(domain, tasklist)
|
36
|
+
.start!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
threads.each { |thr| thr.join }
|
41
|
+
|
42
|
+
|
data/bin/setup
ADDED
data/jflow.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'jflow/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "jflow"
|
8
|
+
spec.version = JFlow::VERSION
|
9
|
+
spec.authors = ["Christophe Verbinnen"]
|
10
|
+
spec.email = ["christophe.verbinnen@lookout.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{SWF Flow framework for jRuby}
|
13
|
+
spec.description = %q{you know, for flow}
|
14
|
+
spec.homepage = "https://github.com/djpate/jflow"
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
18
|
+
if spec.respond_to?(:metadata)
|
19
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
20
|
+
else
|
21
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
22
|
+
end
|
23
|
+
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
spec.bindir = "bin"
|
26
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
spec.add_development_dependency "rspec"
|
32
|
+
|
33
|
+
spec.add_dependency "aws-sdk", "~> 2"
|
34
|
+
spec.add_dependency "hash_validator"
|
35
|
+
spec.add_dependency "slop", "~> 4"
|
36
|
+
end
|
data/lib/jflow.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "jflow/version"
|
2
|
+
require "jflow/activity.rb"
|
3
|
+
require "jflow/activity_mixin.rb"
|
4
|
+
require "jflow/activity_worker.rb"
|
5
|
+
require "jflow/configuration.rb"
|
6
|
+
require "yaml"
|
7
|
+
require "json"
|
8
|
+
require "hash_validator"
|
9
|
+
require 'aws-sdk'
|
10
|
+
|
11
|
+
module JFlow
|
12
|
+
class << self
|
13
|
+
attr_writer :configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configuration
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.reset
|
21
|
+
@configuration = Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure
|
25
|
+
yield(configuration)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.load_activities
|
29
|
+
configuration.load_paths.each do |path|
|
30
|
+
Dir["#{path}/*.rb"].each do |file|
|
31
|
+
configuration.logger.debug "found #{file}"
|
32
|
+
require file
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module JFlow
|
2
|
+
class Activity
|
3
|
+
|
4
|
+
DEFAULT_OPTIONS = {}
|
5
|
+
|
6
|
+
OPTIONS_VALIDATOR = {
|
7
|
+
:version => "string",
|
8
|
+
:domain => "string",
|
9
|
+
:name => "string",
|
10
|
+
:default_task_list => {
|
11
|
+
:name => "string"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_reader :options, :klass
|
16
|
+
|
17
|
+
# Possible options are :
|
18
|
+
# domain: "DomainName", # required
|
19
|
+
# name: "Name", # required
|
20
|
+
# version: "Version", # required
|
21
|
+
# description: "Description",
|
22
|
+
# default_task_start_to_close_timeout: "DurationInSecondsOptional",
|
23
|
+
# default_task_heartbeat_timeout: "DurationInSecondsOptional",
|
24
|
+
# default_task_list: {
|
25
|
+
# name: "Name", # required
|
26
|
+
# },
|
27
|
+
# default_task_priority: "TaskPriority",
|
28
|
+
# default_task_schedule_to_start_timeout: "DurationInSecondsOptional",
|
29
|
+
# default_task_schedule_to_close_timeout: "DurationInSecondsOptional",
|
30
|
+
def initialize(klass, options = {})
|
31
|
+
@klass = klass
|
32
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
33
|
+
@options[:name] = name
|
34
|
+
validate_activity!
|
35
|
+
register_activity unless registered?
|
36
|
+
add_to_activity_mapping
|
37
|
+
end
|
38
|
+
|
39
|
+
def register_activity
|
40
|
+
JFlow.configuration.swf_client.register_activity_type(options)
|
41
|
+
JFlow.configuration.logger.info "Activity #{name} was registered successfuly"
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_to_activity_mapping
|
45
|
+
$activity_map ||= {}
|
46
|
+
$activity_map[name] ||= {}
|
47
|
+
$activity_map[name][options[:version]] = {:class => klass, :options => options}
|
48
|
+
end
|
49
|
+
|
50
|
+
def name
|
51
|
+
@options[:name] || klass.name.to_s.split('::').last.scan(/[A-Z][a-z]*/).join("_").downcase
|
52
|
+
end
|
53
|
+
|
54
|
+
def version
|
55
|
+
@options[:version]
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_activity!
|
59
|
+
validator = HashValidator.validate(@options, OPTIONS_VALIDATOR)
|
60
|
+
raise "Activity #{options[:name]}definition is invalid! #{validator.errors}" unless validator.valid?
|
61
|
+
end
|
62
|
+
|
63
|
+
def registered?
|
64
|
+
response = JFlow.configuration.swf_client.list_activity_types({
|
65
|
+
domain: options[:domain],
|
66
|
+
name: name,
|
67
|
+
registration_status: "REGISTERED"
|
68
|
+
})
|
69
|
+
|
70
|
+
response.type_infos.each do |type_info|
|
71
|
+
if type_info.activity_type.name == name && type_info.activity_type.version == version
|
72
|
+
JFlow.configuration.logger.info "Activity #{name} #{version} is already registered"
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module JFlow
|
2
|
+
module ActivityMixin
|
3
|
+
|
4
|
+
def self.included base
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def activity(name = nil)
|
10
|
+
options = {}
|
11
|
+
options = yield if block_given?
|
12
|
+
options[:name] = name
|
13
|
+
JFlow.configuration.logger.debug "loading #{name}"
|
14
|
+
JFlow::Activity.new(self, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module JFlow
|
2
|
+
class ActivityWorker
|
3
|
+
|
4
|
+
attr_reader :domain, :tasklist
|
5
|
+
|
6
|
+
def initialize(domain, tasklist)
|
7
|
+
@domain = domain
|
8
|
+
@tasklist = tasklist
|
9
|
+
end
|
10
|
+
|
11
|
+
def start!
|
12
|
+
loop do
|
13
|
+
log "Polling for task on #{domain} - #{tasklist}"
|
14
|
+
poll
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def poll
|
21
|
+
response = JFlow.configuration.swf_client.poll_for_activity_task(poll_params)
|
22
|
+
if response.task_token
|
23
|
+
process_task(response)
|
24
|
+
else
|
25
|
+
log "Got no task"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_task(response)
|
30
|
+
log "Got task #{response.task_token}"
|
31
|
+
|
32
|
+
klass = class_for_activity(response.activity_type)
|
33
|
+
raise "Could not find code to run for given activity" unless klass
|
34
|
+
|
35
|
+
begin
|
36
|
+
JFlow.configuration.logger.debug "Started #{klass}#process with #{YAML.load(response.input)}"
|
37
|
+
if response.activity_type.name.split('.').size > 1
|
38
|
+
method = response.activity_type.name.split('.').last
|
39
|
+
else
|
40
|
+
method = "process"
|
41
|
+
end
|
42
|
+
result = klass.new.send(method, YAML.load(response.input)) || true
|
43
|
+
JFlow.configuration.logger.debug "Done #{klass}##{method}"
|
44
|
+
JFlow.configuration.swf_client.respond_activity_task_completed({
|
45
|
+
task_token: response.task_token,
|
46
|
+
result: result,
|
47
|
+
})
|
48
|
+
rescue => e
|
49
|
+
JFlow.configuration.swf_client.respond_activity_task_failed({
|
50
|
+
task_token: response.task_token,
|
51
|
+
reason: e.message,
|
52
|
+
details: e.backtrace.join("\n"),
|
53
|
+
})
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def identity
|
59
|
+
@identity ||= "#{`hostname`.chomp}-#{Thread.current.object_id}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def log(str)
|
63
|
+
JFlow.configuration.logger.info "[#{Thread.current.object_id}] #{str}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def poll_params
|
67
|
+
{
|
68
|
+
domain: domain,
|
69
|
+
task_list: {
|
70
|
+
name: tasklist,
|
71
|
+
},
|
72
|
+
identity: identity,
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def class_for_activity(activity_type)
|
77
|
+
$activity_map[activity_type.name][activity_type.version][:class]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jflow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christophe Verbinnen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '1.10'
|
25
|
+
prerelease: false
|
26
|
+
type: :development
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '10.0'
|
39
|
+
prerelease: false
|
40
|
+
type: :development
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: aws-sdk
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ~>
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '2'
|
67
|
+
prerelease: false
|
68
|
+
type: :runtime
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: hash_validator
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
prerelease: false
|
82
|
+
type: :runtime
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: slop
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4'
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '4'
|
95
|
+
prerelease: false
|
96
|
+
type: :runtime
|
97
|
+
description: you know, for flow
|
98
|
+
email:
|
99
|
+
- christophe.verbinnen@lookout.com
|
100
|
+
executables:
|
101
|
+
- console
|
102
|
+
- jflow_worker
|
103
|
+
- setup
|
104
|
+
extensions: []
|
105
|
+
extra_rdoc_files: []
|
106
|
+
files:
|
107
|
+
- .gitignore
|
108
|
+
- .rspec
|
109
|
+
- .travis.yml
|
110
|
+
- Gemfile
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- bin/console
|
114
|
+
- bin/jflow_worker
|
115
|
+
- bin/setup
|
116
|
+
- jflow.gemspec
|
117
|
+
- lib/jflow.rb
|
118
|
+
- lib/jflow/activity.rb
|
119
|
+
- lib/jflow/activity_mixin.rb
|
120
|
+
- lib/jflow/activity_worker.rb
|
121
|
+
- lib/jflow/configuration.rb
|
122
|
+
- lib/jflow/version.rb
|
123
|
+
homepage: https://github.com/djpate/jflow
|
124
|
+
licenses: []
|
125
|
+
metadata:
|
126
|
+
allowed_push_host: https://rubygems.org
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 2.4.5
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: SWF Flow framework for jRuby
|
147
|
+
test_files: []
|