beez 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,36 @@
1
+ require_relative 'lib/beez/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "beez"
5
+ spec.version = Beez::VERSION
6
+ spec.authors = ["Pierre-Louis Gottfrois"]
7
+ spec.email = ["pierrelouis.gottfrois@gmail.com"]
8
+
9
+ spec.summary = %q{Simple, efficient ruby workers for Zeebe business processes.}
10
+ spec.description = %q{Simple, efficient ruby workers for Zeebe business processes.}
11
+ spec.homepage = "https://github.com/gottfrois/beez"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/gottfrois/beez"
19
+ spec.metadata["changelog_uri"] = "https://github.com/gottfrois/beez/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "zeebe-client", "~> 0.7"
31
+ spec.add_dependency "concurrent-ruby", "~> 1.0"
32
+
33
+ spec.add_development_dependency "pry"
34
+ spec.add_development_dependency "bundler"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "beez"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,139 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0roiw93" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Zeebe Modeler" exporterVersion="0.9.1">
3
+ <bpmn:process id="order-process" isExecutable="true">
4
+ <bpmn:startEvent id="StartEvent_1" name="Order Placed">
5
+ <bpmn:outgoing>SequenceFlow_0l1itgv</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:serviceTask id="ServiceTask_1uaxkgt" name="Initiate Payment">
8
+ <bpmn:extensionElements>
9
+ <zeebe:taskDefinition type="initiate-payment" />
10
+ </bpmn:extensionElements>
11
+ <bpmn:incoming>SequenceFlow_0l1itgv</bpmn:incoming>
12
+ <bpmn:outgoing>SequenceFlow_05wimmt</bpmn:outgoing>
13
+ </bpmn:serviceTask>
14
+ <bpmn:sequenceFlow id="SequenceFlow_0l1itgv" sourceRef="StartEvent_1" targetRef="ServiceTask_1uaxkgt" />
15
+ <bpmn:intermediateCatchEvent id="IntermediateCatchEvent_178qswy" name="Payment Received">
16
+ <bpmn:incoming>SequenceFlow_05wimmt</bpmn:incoming>
17
+ <bpmn:outgoing>SequenceFlow_0sdhelb</bpmn:outgoing>
18
+ <bpmn:messageEventDefinition messageRef="Message_1jdabrh" />
19
+ </bpmn:intermediateCatchEvent>
20
+ <bpmn:sequenceFlow id="SequenceFlow_05wimmt" sourceRef="ServiceTask_1uaxkgt" targetRef="IntermediateCatchEvent_178qswy" />
21
+ <bpmn:exclusiveGateway id="ExclusiveGateway_0xtem5z" name="Order Value?" default="SequenceFlow_1of2ef2">
22
+ <bpmn:incoming>SequenceFlow_0sdhelb</bpmn:incoming>
23
+ <bpmn:outgoing>SequenceFlow_1of2ef2</bpmn:outgoing>
24
+ <bpmn:outgoing>SequenceFlow_1qfaoce</bpmn:outgoing>
25
+ </bpmn:exclusiveGateway>
26
+ <bpmn:sequenceFlow id="SequenceFlow_0sdhelb" sourceRef="IntermediateCatchEvent_178qswy" targetRef="ExclusiveGateway_0xtem5z" />
27
+ <bpmn:serviceTask id="ServiceTask_0ms04gz" name="Ship Without Insurance">
28
+ <bpmn:extensionElements>
29
+ <zeebe:taskDefinition type="ship-without-insurance" />
30
+ </bpmn:extensionElements>
31
+ <bpmn:incoming>SequenceFlow_1of2ef2</bpmn:incoming>
32
+ <bpmn:outgoing>SequenceFlow_1pxhmpe</bpmn:outgoing>
33
+ </bpmn:serviceTask>
34
+ <bpmn:sequenceFlow id="SequenceFlow_1of2ef2" sourceRef="ExclusiveGateway_0xtem5z" targetRef="ServiceTask_0ms04gz" />
35
+ <bpmn:serviceTask id="ServiceTask_0tw27bj" name="Ship With Insurance">
36
+ <bpmn:extensionElements>
37
+ <zeebe:taskDefinition type="ship-with-insurance" />
38
+ </bpmn:extensionElements>
39
+ <bpmn:incoming>SequenceFlow_1qfaoce</bpmn:incoming>
40
+ <bpmn:outgoing>SequenceFlow_0dvg03l</bpmn:outgoing>
41
+ </bpmn:serviceTask>
42
+ <bpmn:sequenceFlow id="SequenceFlow_1qfaoce" name="&#62;$100" sourceRef="ExclusiveGateway_0xtem5z" targetRef="ServiceTask_0tw27bj">
43
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=orderValue &gt;= 100</bpmn:conditionExpression>
44
+ </bpmn:sequenceFlow>
45
+ <bpmn:exclusiveGateway id="ExclusiveGateway_0y9y7j8">
46
+ <bpmn:incoming>SequenceFlow_1pxhmpe</bpmn:incoming>
47
+ <bpmn:incoming>SequenceFlow_0dvg03l</bpmn:incoming>
48
+ <bpmn:outgoing>SequenceFlow_0p15rvb</bpmn:outgoing>
49
+ </bpmn:exclusiveGateway>
50
+ <bpmn:sequenceFlow id="SequenceFlow_1pxhmpe" sourceRef="ServiceTask_0ms04gz" targetRef="ExclusiveGateway_0y9y7j8" />
51
+ <bpmn:sequenceFlow id="SequenceFlow_0dvg03l" sourceRef="ServiceTask_0tw27bj" targetRef="ExclusiveGateway_0y9y7j8" />
52
+ <bpmn:endEvent id="EndEvent_146mj14" name="Order Fulfilled">
53
+ <bpmn:incoming>SequenceFlow_0p15rvb</bpmn:incoming>
54
+ </bpmn:endEvent>
55
+ <bpmn:sequenceFlow id="SequenceFlow_0p15rvb" sourceRef="ExclusiveGateway_0y9y7j8" targetRef="EndEvent_146mj14" />
56
+ </bpmn:process>
57
+ <bpmn:message id="Message_1jdabrh" name="payment-received">
58
+ <bpmn:extensionElements>
59
+ <zeebe:subscription correlationKey="=orderId" />
60
+ </bpmn:extensionElements>
61
+ </bpmn:message>
62
+ <bpmndi:BPMNDiagram id="BPMNDiagram_1">
63
+ <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="order-process">
64
+ <bpmndi:BPMNEdge id="SequenceFlow_0p15rvb_di" bpmnElement="SequenceFlow_0p15rvb">
65
+ <di:waypoint x="801" y="121" />
66
+ <di:waypoint x="851" y="121" />
67
+ </bpmndi:BPMNEdge>
68
+ <bpmndi:BPMNEdge id="SequenceFlow_0dvg03l_di" bpmnElement="SequenceFlow_0dvg03l">
69
+ <di:waypoint x="701" y="231" />
70
+ <di:waypoint x="776" y="231" />
71
+ <di:waypoint x="776" y="146" />
72
+ </bpmndi:BPMNEdge>
73
+ <bpmndi:BPMNEdge id="SequenceFlow_1pxhmpe_di" bpmnElement="SequenceFlow_1pxhmpe">
74
+ <di:waypoint x="701" y="121" />
75
+ <di:waypoint x="751" y="121" />
76
+ </bpmndi:BPMNEdge>
77
+ <bpmndi:BPMNEdge id="SequenceFlow_1qfaoce_di" bpmnElement="SequenceFlow_1qfaoce">
78
+ <di:waypoint x="526" y="146" />
79
+ <di:waypoint x="526" y="231" />
80
+ <di:waypoint x="601" y="231" />
81
+ <bpmndi:BPMNLabel>
82
+ <dc:Bounds x="543" y="210" width="31" height="14" />
83
+ </bpmndi:BPMNLabel>
84
+ </bpmndi:BPMNEdge>
85
+ <bpmndi:BPMNEdge id="SequenceFlow_1of2ef2_di" bpmnElement="SequenceFlow_1of2ef2">
86
+ <di:waypoint x="551" y="121" />
87
+ <di:waypoint x="601" y="121" />
88
+ </bpmndi:BPMNEdge>
89
+ <bpmndi:BPMNEdge id="SequenceFlow_0sdhelb_di" bpmnElement="SequenceFlow_0sdhelb">
90
+ <di:waypoint x="451" y="121" />
91
+ <di:waypoint x="501" y="121" />
92
+ </bpmndi:BPMNEdge>
93
+ <bpmndi:BPMNEdge id="SequenceFlow_05wimmt_di" bpmnElement="SequenceFlow_05wimmt">
94
+ <di:waypoint x="365" y="121" />
95
+ <di:waypoint x="415" y="121" />
96
+ </bpmndi:BPMNEdge>
97
+ <bpmndi:BPMNEdge id="SequenceFlow_0l1itgv_di" bpmnElement="SequenceFlow_0l1itgv">
98
+ <di:waypoint x="215" y="121" />
99
+ <di:waypoint x="265" y="121" />
100
+ </bpmndi:BPMNEdge>
101
+ <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
102
+ <dc:Bounds x="179" y="103" width="36" height="36" />
103
+ <bpmndi:BPMNLabel>
104
+ <dc:Bounds x="165" y="146" width="65" height="14" />
105
+ </bpmndi:BPMNLabel>
106
+ </bpmndi:BPMNShape>
107
+ <bpmndi:BPMNShape id="ServiceTask_1uaxkgt_di" bpmnElement="ServiceTask_1uaxkgt">
108
+ <dc:Bounds x="265" y="81" width="100" height="80" />
109
+ </bpmndi:BPMNShape>
110
+ <bpmndi:BPMNShape id="IntermediateCatchEvent_178qswy_di" bpmnElement="IntermediateCatchEvent_178qswy">
111
+ <dc:Bounds x="415" y="103" width="36" height="36" />
112
+ <bpmndi:BPMNLabel>
113
+ <dc:Bounds x="410" y="146" width="46" height="27" />
114
+ </bpmndi:BPMNLabel>
115
+ </bpmndi:BPMNShape>
116
+ <bpmndi:BPMNShape id="ExclusiveGateway_0xtem5z_di" bpmnElement="ExclusiveGateway_0xtem5z" isMarkerVisible="true">
117
+ <dc:Bounds x="501" y="96" width="50" height="50" />
118
+ <bpmndi:BPMNLabel>
119
+ <dc:Bounds x="493" y="72" width="65" height="14" />
120
+ </bpmndi:BPMNLabel>
121
+ </bpmndi:BPMNShape>
122
+ <bpmndi:BPMNShape id="ServiceTask_0ms04gz_di" bpmnElement="ServiceTask_0ms04gz">
123
+ <dc:Bounds x="601" y="81" width="100" height="80" />
124
+ </bpmndi:BPMNShape>
125
+ <bpmndi:BPMNShape id="ServiceTask_0tw27bj_di" bpmnElement="ServiceTask_0tw27bj">
126
+ <dc:Bounds x="601" y="191" width="100" height="80" />
127
+ </bpmndi:BPMNShape>
128
+ <bpmndi:BPMNShape id="ExclusiveGateway_0y9y7j8_di" bpmnElement="ExclusiveGateway_0y9y7j8" isMarkerVisible="true">
129
+ <dc:Bounds x="751" y="96" width="50" height="50" />
130
+ </bpmndi:BPMNShape>
131
+ <bpmndi:BPMNShape id="EndEvent_146mj14_di" bpmnElement="EndEvent_146mj14">
132
+ <dc:Bounds x="851" y="103" width="36" height="36" />
133
+ <bpmndi:BPMNLabel>
134
+ <dc:Bounds x="834" y="146" width="70" height="14" />
135
+ </bpmndi:BPMNLabel>
136
+ </bpmndi:BPMNShape>
137
+ </bpmndi:BPMNPlane>
138
+ </bpmndi:BPMNDiagram>
139
+ </bpmn:definitions>
@@ -0,0 +1,49 @@
1
+ require "beez"
2
+
3
+ module Workers
4
+ class InitiatePaymentWorker
5
+ include ::Beez::Worker
6
+
7
+ type "initiate-payment"
8
+ max_jobs_to_activate 5
9
+ poll_interval 1
10
+ timeout 30
11
+
12
+ def process(job)
13
+ rand(35).times do |i|
14
+ logger.info "Processing job #{job.type} #{job.key} by waiting #{i}s"
15
+ sleep 1
16
+ end
17
+ end
18
+ end
19
+
20
+ class ShipWithInsuranceWorker
21
+ include ::Beez::Worker
22
+
23
+ type "ship-with-insurance"
24
+ max_jobs_to_activate 5
25
+ poll_interval 1
26
+
27
+ def process(job)
28
+ rand(35).times do |i|
29
+ logger.info "Processing job #{job.type} #{job.key} by waiting #{i}s"
30
+ sleep 1
31
+ end
32
+ end
33
+ end
34
+
35
+ class ShipWithoutInsuranceWorker
36
+ include ::Beez::Worker
37
+
38
+ type "ship-without-insurance"
39
+ max_jobs_to_activate 5
40
+ poll_interval 1
41
+
42
+ def process(job)
43
+ rand(35).times do |i|
44
+ logger.info "Processing job #{job.type} #{job.key} by waiting #{i}s"
45
+ sleep 1
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "beez/cli"
4
+
5
+ begin
6
+ cli = ::Beez::CLI.instance
7
+ cli.parse
8
+ cli.run
9
+ rescue => e
10
+ raise e if $DEBUG
11
+ STDERR.puts e.message
12
+ STDERR.puts e.backtrace.join("\n")
13
+ exit 1
14
+ end
@@ -0,0 +1,26 @@
1
+ require 'concurrent'
2
+
3
+ require 'beez/configurable'
4
+ require 'beez/Loggable'
5
+ require 'beez/client'
6
+ require 'beez/worker'
7
+ require 'beez/version'
8
+
9
+ module Beez
10
+ extend ::Beez::Configurable
11
+ extend ::Beez::Loggable
12
+
13
+ # class Error < StandardError; end
14
+
15
+ def self.register_worker(worker)
16
+ self.workers << worker
17
+ end
18
+
19
+ def self.workers
20
+ @workers ||= []
21
+ end
22
+
23
+ def self.client
24
+ @client ||= ::Beez::Client.new
25
+ end
26
+ end
@@ -0,0 +1,143 @@
1
+ require 'singleton'
2
+ require 'optparse'
3
+ require 'fileutils'
4
+ require 'beez'
5
+ require 'beez/launcher'
6
+
7
+ $stdout.sync = true
8
+
9
+ module Beez
10
+ class CLI
11
+ include Singleton
12
+
13
+ attr_accessor :launcher
14
+
15
+ def parse(argv = ARGV)
16
+ parse_options(argv)
17
+ end
18
+
19
+ def run
20
+ boot
21
+
22
+ self_read, self_write = IO.pipe
23
+ sigs = %w[INT TERM]
24
+ sigs.each do |sig|
25
+ trap sig do
26
+ self_write.write("#{sig}\n")
27
+ end
28
+ rescue ArgumentError
29
+ logger.warn "Signal #{sig} not supported"
30
+ end
31
+
32
+ launch(self_read)
33
+ end
34
+
35
+ private
36
+
37
+ def parse_options(argv)
38
+ option_parser.parse!(argv)
39
+ end
40
+
41
+ def option_parser
42
+ OptionParser.new.tap do |p|
43
+ p.on "-e", "--env ENV", "Application environment" do |arg|
44
+ config.env = arg
45
+ end
46
+
47
+ p.on "-r", "--require [PATH|DIR]", "Location of Rails application with workers or file to require" do |arg|
48
+ if !File.exist?(arg) ||
49
+ (File.directory?(arg) && !File.exist?("#{arg}/config/application.rb"))
50
+ raise ArgumentError, "#{arg} is not a ruby file nor a rails application"
51
+ else
52
+ config.require = arg
53
+ end
54
+ end
55
+
56
+ p.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
57
+ timeout = Integer(arg)
58
+ raise ArgumentError, "timeout must be a positive integer" if timeout <= 0
59
+ config.timeout = timeout
60
+ end
61
+
62
+ p.on "-v", "--verbose", "Print more verbose output" do |arg|
63
+ ::Beez.logger.level = ::Logger::DEBUG
64
+ end
65
+
66
+ p.on "-V", "--version", "Print version and exit" do |arg|
67
+ puts "Beez #{::Beez::VERSION}"
68
+ exit(0)
69
+ end
70
+
71
+ p.banner = "Usage: beez [options]"
72
+ p.on_tail "-h", "--help", "Show help" do
73
+ puts p
74
+
75
+ exit(1)
76
+ end
77
+ end
78
+ end
79
+
80
+ def boot
81
+ ENV["RACK_ENV"] = ENV["RAILS_ENV"] = config.env
82
+
83
+ if File.directory?(config.require)
84
+ require 'rails'
85
+ if ::Rails::VERSION::MAJOR < 4
86
+ raise "Beez does not supports this version of Rails"
87
+ else
88
+ require File.expand_path("#{config.require}/config/environment.rb")
89
+ logger.info "Booted Rails #{::Rails.version} application in #{config.env} environment"
90
+ end
91
+ else
92
+ require config.require
93
+ end
94
+ end
95
+
96
+ def launch(self_read)
97
+ @launcher = ::Beez::Launcher.new
98
+
99
+ if config.env == "development" && $stdout.tty?
100
+ logger.info "Starting processing, hit Ctrl-C to stop"
101
+ end
102
+
103
+ begin
104
+ launcher.start
105
+
106
+ while readable_io = IO.select([self_read])
107
+ signal = readable_io.first[0].gets.strip
108
+ handle_signal(signal)
109
+ end
110
+ rescue Interrupt
111
+ logger.info "Shutting down"
112
+ launcher.stop
113
+ logger.info "Bye!"
114
+
115
+ exit(0)
116
+ end
117
+ end
118
+
119
+ def handle_signal(signal)
120
+ handler = signal_handlers[signal]
121
+ if handler
122
+ handler.call(self)
123
+ else
124
+ logger.warn "No signal handler for #{signal}"
125
+ end
126
+ end
127
+
128
+ def signal_handlers
129
+ {
130
+ "INT" => ->(cli) { raise Interrupt },
131
+ "TERM" => ->(cli) { raise Interrupt },
132
+ }
133
+ end
134
+
135
+ def config
136
+ ::Beez.config
137
+ end
138
+
139
+ def logger
140
+ ::Beez.logger
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,97 @@
1
+ require 'zeebe/client'
2
+
3
+ module Beez
4
+ class Client
5
+
6
+ attr_reader :client
7
+
8
+ def initialize(url: ::Beez.config.zeebe_url, opts: :this_channel_is_insecure)
9
+ @client = ::Zeebe::Client::GatewayProtocol::Gateway::Stub.new(url, opts)
10
+ end
11
+
12
+ def activate_jobs(params = {})
13
+ run(:activate_jobs,
14
+ ::Zeebe::Client::GatewayProtocol::ActivateJobsRequest.new(params)
15
+ )
16
+ end
17
+
18
+ def cancel_workflow_instance(params = {})
19
+ run(:cancel_workflow_instance,
20
+ ::Zeebe::Client::GatewayProtocol::CancelWorkflowInstanceRequest.new(params)
21
+ )
22
+ end
23
+
24
+ def complete_job(params = {})
25
+ run(:complete_job,
26
+ ::Zeebe::Client::GatewayProtocol::CompleteJobRequest.new(params)
27
+ )
28
+ end
29
+
30
+ def create_workflow_instance(params = {})
31
+ run(:create_workflow_instance,
32
+ ::Zeebe::Client::GatewayProtocol::CreateWorkflowInstanceRequest.new(params)
33
+ )
34
+ end
35
+
36
+ def deploy_workflow(params = {})
37
+ run(:deploy_workflow,
38
+ ::Zeebe::Client::GatewayProtocol::DeployWorkflowRequest.new(params)
39
+ )
40
+ end
41
+
42
+ def fail_job(params = {})
43
+ run(:fail_job,
44
+ ::Zeebe::Client::GatewayProtocol::FailJobRequest.new(params)
45
+ )
46
+ end
47
+
48
+ def throw_error(params = {})
49
+ run(:throw_error,
50
+ ::Zeebe::Client::GatewayProtocol::ThrowErrorRequest.new(params)
51
+ )
52
+ end
53
+
54
+ def publish_message(params = {})
55
+ run(:publish_message,
56
+ ::Zeebe::Client::GatewayProtocol::PublishMessageRequest.new(params)
57
+ )
58
+ end
59
+
60
+ def resolve_incident(params = {})
61
+ run(:resolve_incident,
62
+ ::Zeebe::Client::GatewayProtocol::ResolveIncidentRequest.new(params)
63
+ )
64
+ end
65
+
66
+ def set_variables(params = {})
67
+ run(:set_variables,
68
+ ::Zeebe::Client::GatewayProtocol::SetVariablesRequest.new(params)
69
+ )
70
+ end
71
+
72
+ def topology(params = {})
73
+ run(:topology,
74
+ ::Zeebe::Client::GatewayProtocol::TopologyRequest.new(params)
75
+ )
76
+ end
77
+
78
+ def update_job_retries(params = {})
79
+ run(:update_job_retries,
80
+ ::Zeebe::Client::GatewayProtocol::UpdateJobRetriesRequest.new(params)
81
+ )
82
+ end
83
+
84
+ private
85
+
86
+ def run(method, params = {})
87
+ client.public_send(method, params)
88
+ rescue ::GRPC::Unavailable => exception
89
+ logger.error exception.message
90
+ raise exception
91
+ end
92
+
93
+ def logger
94
+ ::Beez.logger
95
+ end
96
+ end
97
+ end