beez 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 +11 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +173 -0
- data/LICENSE.txt +21 -0
- data/README.md +139 -0
- data/Rakefile +6 -0
- data/beez.gemspec +36 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bpmn/order-process.bpmn +139 -0
- data/examples/workers.rb +49 -0
- data/exe/beez +14 -0
- data/lib/beez.rb +26 -0
- data/lib/beez/cli.rb +143 -0
- data/lib/beez/client.rb +97 -0
- data/lib/beez/configurable.rb +13 -0
- data/lib/beez/configuration.rb +14 -0
- data/lib/beez/launcher.rb +35 -0
- data/lib/beez/loggable.rb +15 -0
- data/lib/beez/processor.rb +103 -0
- data/lib/beez/rails.rb +29 -0
- data/lib/beez/supervisor.rb +38 -0
- data/lib/beez/version.rb +3 -0
- data/lib/beez/worker.rb +163 -0
- metadata +146 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module Beez
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
attr_accessor :env, :logger, :require, :timeout, :zeebe_url
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@env = ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
8
|
+
@logger = Logger.new($stdout)
|
9
|
+
@require = "."
|
10
|
+
@timeout = 30
|
11
|
+
@zeebe_url = ENV['ZEEBE_URL'] || 'localhost:26500'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'beez/supervisor'
|
2
|
+
|
3
|
+
module Beez
|
4
|
+
class Launcher
|
5
|
+
|
6
|
+
attr_reader :supervisor
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@supervisor = ::Beez::Supervisor.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Starts the supervisor and job processors.
|
13
|
+
def start
|
14
|
+
supervisor.start
|
15
|
+
end
|
16
|
+
|
17
|
+
# Tells the supervisor to stop processing any more jobs.
|
18
|
+
def quiet
|
19
|
+
supervisor.quiet
|
20
|
+
end
|
21
|
+
|
22
|
+
# Tells the supervisor to stop job processors. This method blocks until
|
23
|
+
# all processors are complete and stopped. It can take up to configurable
|
24
|
+
# timeout.
|
25
|
+
def stop
|
26
|
+
supervisor.stop
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def client
|
32
|
+
::Beez.client
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Beez
|
2
|
+
class Processor
|
3
|
+
|
4
|
+
attr_reader :client, :worker_class, :busy_count, :timer
|
5
|
+
|
6
|
+
def initialize(client: ::Beez.client, worker_class:)
|
7
|
+
@client = client
|
8
|
+
@worker_class = worker_class
|
9
|
+
@busy_count = ::Concurrent::AtomicFixnum.new(0)
|
10
|
+
@timer = ::Concurrent::TimerTask.new(
|
11
|
+
run_now: true,
|
12
|
+
execution_interval: worker_poll_interval,
|
13
|
+
timeout_interval: worker_timeout
|
14
|
+
) { run }
|
15
|
+
end
|
16
|
+
|
17
|
+
def start
|
18
|
+
timer.execute
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop
|
23
|
+
timer.shutdown
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def should_activate_jobs?
|
28
|
+
busy_count.value <= worker_max_jobs_to_activate
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def run
|
34
|
+
fetch if should_activate_jobs?
|
35
|
+
end
|
36
|
+
|
37
|
+
def fetch
|
38
|
+
activate_jobs_request.each do |response|
|
39
|
+
busy_count.increment(response.jobs.count)
|
40
|
+
response.jobs.each do |job|
|
41
|
+
::Concurrent::Future.execute do
|
42
|
+
process(job)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def process(job)
|
49
|
+
worker = worker_class.new(client)
|
50
|
+
begin
|
51
|
+
worker.process(job)
|
52
|
+
worker.complete_job(job)
|
53
|
+
rescue => exception
|
54
|
+
worker.fail_job(job, reason: exception.message)
|
55
|
+
raise exception
|
56
|
+
ensure
|
57
|
+
busy_count.decrement
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def activate_jobs_request
|
62
|
+
client.activate_jobs(
|
63
|
+
type: worker_type,
|
64
|
+
worker: worker_name,
|
65
|
+
timeout: worker_timeout * 1000,
|
66
|
+
maxJobsToActivate: max_jobs_to_activate,
|
67
|
+
fetchVariable: worker_variables_to_fetch,
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def worker_type
|
72
|
+
worker_class.get_type
|
73
|
+
end
|
74
|
+
|
75
|
+
def worker_name
|
76
|
+
worker_class.get_name
|
77
|
+
end
|
78
|
+
|
79
|
+
def worker_max_jobs_to_activate
|
80
|
+
worker_class.get_max_jobs_to_activate
|
81
|
+
end
|
82
|
+
|
83
|
+
def worker_timeout
|
84
|
+
worker_class.get_timeout
|
85
|
+
end
|
86
|
+
|
87
|
+
def worker_variables_to_fetch
|
88
|
+
worker_class.get_variables_to_fetch
|
89
|
+
end
|
90
|
+
|
91
|
+
def worker_poll_interval
|
92
|
+
worker_class.get_poll_interval
|
93
|
+
end
|
94
|
+
|
95
|
+
def max_jobs_to_activate
|
96
|
+
worker_max_jobs_to_activate - busy_count.value
|
97
|
+
end
|
98
|
+
|
99
|
+
def logger
|
100
|
+
::Beez.logger
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/beez/rails.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Beez
|
2
|
+
class Rails < ::Rails::Engine
|
3
|
+
class Reloader
|
4
|
+
def initialize(app = ::Rails.application)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
@app.reloader.wrap do
|
10
|
+
yield
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"#<Beez::Rails::Reloader @app=#{@app.class.name}>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# This hook happens after all initializers are run, just before returning
|
20
|
+
# from config/environment.rb back to beez/cli.rb.
|
21
|
+
#
|
22
|
+
# None of this matters on the client-side, only within the Beez process itself.
|
23
|
+
config.after_initialize do
|
24
|
+
Beez.configure_server do |_|
|
25
|
+
Beez.options[:reloader] = Beez::Rails::Reloader.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'beez/processor'
|
2
|
+
|
3
|
+
module Beez
|
4
|
+
class Supervisor
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@processors = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
@processors = workers.map do |worker_class|
|
12
|
+
processor = ::Beez::Processor.new(worker_class: worker_class)
|
13
|
+
processor.start
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def quiet
|
18
|
+
logger.info "Terminating workers"
|
19
|
+
@processors.each(&:stop)
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop(timeout: ::Beez.config.timeout)
|
23
|
+
quiet
|
24
|
+
logger.info "Pausing #{timeout}s to allow workers to finish..."
|
25
|
+
sleep timeout
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def workers
|
31
|
+
::Beez.workers.to_a
|
32
|
+
end
|
33
|
+
|
34
|
+
def logger
|
35
|
+
::Beez.logger
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/beez/version.rb
ADDED
data/lib/beez/worker.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Beez
|
4
|
+
module Worker
|
5
|
+
attr_accessor :client, :type, :max_jobs_to_activate, :poll_interval, :timeout, :variables
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
Beez.register_worker(base)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(client)
|
13
|
+
@client = client
|
14
|
+
end
|
15
|
+
|
16
|
+
def complete_job(job, variables: {})
|
17
|
+
logger.info "Completed processing job #{job.type} #{job.key}"
|
18
|
+
client.complete_job(
|
19
|
+
jobKey: job.key,
|
20
|
+
variables: Hash(variables).to_json,
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def fail_job(job, reason: "")
|
25
|
+
logger.error "Failed processing job #{job.type} #{job.key}: #{reason}"
|
26
|
+
client.fail_job(
|
27
|
+
jobKey: job.key,
|
28
|
+
retries: job.retries - 1,
|
29
|
+
errorMessage: reason,
|
30
|
+
)
|
31
|
+
rescue => e
|
32
|
+
logger.error e.message
|
33
|
+
end
|
34
|
+
|
35
|
+
def logger
|
36
|
+
::Beez.logger
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
# Sets the type of service task the worker should subscribe to.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# class MyWorker
|
44
|
+
# include ::Beez::Worker
|
45
|
+
# type "some-service-task-type"
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# @param [String] type
|
49
|
+
# @return [String]
|
50
|
+
def type(type)
|
51
|
+
@type = type
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the type of service task the worker should subscribe to.
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
def get_type
|
58
|
+
@type
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets the maximum number of jobs to send to the worker for processing at once.
|
62
|
+
# As jobs get completed by the worker, more jobs will be sent to the worker
|
63
|
+
# but always within this limit.
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# class MyWorker
|
67
|
+
# include ::Beez::Worker
|
68
|
+
# max_jobs_to_activate 5
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @param [Integer] max_jobs_to_activate
|
72
|
+
# @return [Integer]
|
73
|
+
def max_jobs_to_activate(max_jobs_to_activate)
|
74
|
+
@max_jobs_to_activate = max_jobs_to_activate
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the maximum number of jobs to send to the worker for processing at once.
|
78
|
+
# As jobs get completed by the worker, more jobs will be sent to the worker
|
79
|
+
# but always within this limit.
|
80
|
+
#
|
81
|
+
# @return [Integer]
|
82
|
+
def get_max_jobs_to_activate
|
83
|
+
@max_jobs_to_activate || 1
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets the interval duration in seconds between polls to the broker.
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# class MyWorker
|
90
|
+
# include ::Beez::Worker
|
91
|
+
# poll_interval 5
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# @param [Integer] poll_interval
|
95
|
+
# @return [Integer]
|
96
|
+
def poll_interval(poll_interval)
|
97
|
+
@poll_interval = poll_interval
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns the interval duration in seconds between polls to the broker.
|
101
|
+
#
|
102
|
+
# @return [Integer]
|
103
|
+
def get_poll_interval
|
104
|
+
@poll_interval || 5
|
105
|
+
end
|
106
|
+
|
107
|
+
# Sets the time in seconds the worker has to process the job before
|
108
|
+
# the broker consider it as expired and can schedule it to another worker.
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# class MyWorker
|
112
|
+
# include ::Beez::Worker
|
113
|
+
# timeout 30
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# @param [Integer] timeout
|
117
|
+
# @return [Integer]
|
118
|
+
def timeout(timeout)
|
119
|
+
@timeout = timeout
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns the time in seconds the worker has to process the job before
|
123
|
+
# the broker consider it as expired and can schedule it to another worker.
|
124
|
+
#
|
125
|
+
# @return [Integer]
|
126
|
+
def get_timeout
|
127
|
+
@timeout || 30
|
128
|
+
end
|
129
|
+
|
130
|
+
# Sets the worker's variables to fetch from the broker when polling for new
|
131
|
+
# jobs.
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# class MyWorker
|
135
|
+
# include ::Beez::Worker
|
136
|
+
# variables [:foo, :bar]
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# @param [Array<String, Symbol>] variables
|
140
|
+
# @return [Array<String, Symbol>]
|
141
|
+
def variables(variables)
|
142
|
+
@variables = variables
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns the worker's variables to fetch from the broker when polling for new
|
146
|
+
# jobs.
|
147
|
+
#
|
148
|
+
# @return [Array<String, Symbol>]
|
149
|
+
def get_variables_to_fetch
|
150
|
+
@variables.to_a
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns the worker's name.
|
154
|
+
#
|
155
|
+
# @return [String]
|
156
|
+
def get_name
|
157
|
+
name = self.name.gsub(/::/, ':')
|
158
|
+
name.gsub!(/([^A-Z:])([A-Z])/) { "#{$1}_#{$2}" }
|
159
|
+
name.downcase
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: beez
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pierre-Louis Gottfrois
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-07-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: zeebe-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description: Simple, efficient ruby workers for Zeebe business processes.
|
84
|
+
email:
|
85
|
+
- pierrelouis.gottfrois@gmail.com
|
86
|
+
executables:
|
87
|
+
- beez
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".ruby-version"
|
94
|
+
- CHANGELOG.md
|
95
|
+
- CODE_OF_CONDUCT.md
|
96
|
+
- Gemfile
|
97
|
+
- Gemfile.lock
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
100
|
+
- Rakefile
|
101
|
+
- beez.gemspec
|
102
|
+
- bin/console
|
103
|
+
- bin/setup
|
104
|
+
- bpmn/order-process.bpmn
|
105
|
+
- examples/workers.rb
|
106
|
+
- exe/beez
|
107
|
+
- lib/beez.rb
|
108
|
+
- lib/beez/cli.rb
|
109
|
+
- lib/beez/client.rb
|
110
|
+
- lib/beez/configurable.rb
|
111
|
+
- lib/beez/configuration.rb
|
112
|
+
- lib/beez/launcher.rb
|
113
|
+
- lib/beez/loggable.rb
|
114
|
+
- lib/beez/processor.rb
|
115
|
+
- lib/beez/rails.rb
|
116
|
+
- lib/beez/supervisor.rb
|
117
|
+
- lib/beez/version.rb
|
118
|
+
- lib/beez/worker.rb
|
119
|
+
homepage: https://github.com/gottfrois/beez
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata:
|
123
|
+
allowed_push_host: https://rubygems.org
|
124
|
+
homepage_uri: https://github.com/gottfrois/beez
|
125
|
+
source_code_uri: https://github.com/gottfrois/beez
|
126
|
+
changelog_uri: https://github.com/gottfrois/beez/CHANGELOG.md
|
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: 2.3.0
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubygems_version: 3.0.8
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Simple, efficient ruby workers for Zeebe business processes.
|
146
|
+
test_files: []
|