beez 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ require 'beez/configuration'
2
+
3
+ module Beez
4
+ module Configurable
5
+ def config
6
+ @config ||= ::Beez::Configuration.new
7
+ end
8
+
9
+ def configure
10
+ yield config if block_given?
11
+ end
12
+ end
13
+ end
@@ -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,15 @@
1
+ module Beez
2
+ module Loggable
3
+ def logger
4
+ @logger || setup_logger
5
+ end
6
+
7
+ def logger=(logger)
8
+ @logger = logger
9
+ end
10
+
11
+ def setup_logger
12
+ @logger = Beez.config.logger
13
+ end
14
+ end
15
+ 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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Beez
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -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: []