bi-frost 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61a3243740e3d642efe0184d5c64d4ad11e72bff
4
- data.tar.gz: 3834b3af2f9541dd7222a2ebf3e266f9430db2ea
3
+ metadata.gz: 363ad309cb14525b8eff19191a79063afbd1dafa
4
+ data.tar.gz: ca5ff194604f4bfd3748082c40cfb4b5252f20be
5
5
  SHA512:
6
- metadata.gz: 764a14af9175bf5ffd9f25d8e1d84aa6fd31988db87da0cca2db0bc262715d669b66e591892b6a7e7f017899ad6e870813781ac25dd98860e7c519faee77ecfa
7
- data.tar.gz: 1319f4d4eb92d423485943ecdbdd941f68c78b9360b584213c442f1f8f5ea735e22e1f044e0a8e40e02d37c1f160ada2df9b96e89685ffdb2b22354a8a76b0a7
6
+ metadata.gz: 6e01794fc41e75b97540793609859481ea476d3f0029e30b2451dac5438e7afc73cf4d868678c9e718a109ad83d9b3010cb0d2363cb420fe9f33c20b09ecb230
7
+ data.tar.gz: bafa72e44054663f88246a33e072b379747e17969c78112cdeb854c193eb4637ebe37d1c53ecfb433f0fec0368ac1bbd132a148f96c5b1b4a004b95c601616bb
data/lib/bifrost.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'bifrost/entity'
1
2
  require 'bifrost/message'
2
3
  require 'bifrost/topic'
3
4
  require 'bifrost/subscriber'
@@ -8,11 +9,15 @@ require 'bifrost/worker'
8
9
  module Bifrost
9
10
  # Simple utlity that creates a topic and a single subscriber for the given
10
11
  # topic. The topic is returned
11
- def self.create_topic_with_subscriber(topic_name, sub_name)
12
- topic = Bifrost::Topic.new(topic_name)
12
+ def self.create_topic_with_subscriber(topic, subscriber)
13
+ topic = Bifrost::Topic.new(topic)
13
14
  topic.save
14
- subscriber = Bifrost::Subscriber.new(sub_name)
15
- topic.add_subscriber(subscriber)
15
+ topic.add_subscriber(Bifrost::Subscriber.new(subscriber))
16
16
  topic
17
17
  end
18
+
19
+ # Creates a manager instance
20
+ def self.manager
21
+ Bifrost::Manager.new
22
+ end
18
23
  end
@@ -6,44 +6,69 @@ module Bifrost
6
6
  # This class is used to handle the setup and execution of multiple listeners
7
7
  class Manager
8
8
  include Celluloid
9
+ include Celluloid::Internals::Logger
10
+ include Celluloid::Notifications
9
11
 
10
12
  # The supervisor needs to be notified when a worker dies, it also needs to
11
13
  # protect itself from harm
12
14
  trap_exit :worker_died
13
15
 
16
+ # Initialisation of the Manager sets up a subscriber, which informs the manager
17
+ # when the worker is ready to begin work
18
+ def initialize
19
+ subscribe('worker_ready', :worker_ready)
20
+ end
21
+
14
22
  # A supervised worker can be added to the current collection of supervised workers
15
23
  # this also starts the actor
16
- def add(topic_name, subscriber_name, proc)
17
- if topic_name.nil? || subscriber_name.nil? || proc.nil?
24
+ def add(topic, subscriber, proc)
25
+ if topic.nil? || subscriber.nil? || proc.nil?
18
26
  raise InvalidWorkerDefinitionError, 'Invalid worker'
19
27
  else
20
- @supervisor = Worker.supervise(
21
- as: Worker.supervisor_handle(topic_name, subscriber_name),
22
- args: [topic_name, subscriber_name, proc]
23
- )
24
- # Link the worker to the supervisor so if the worker misbehaves the supervisor is alerted
25
- # to this poor behaviour, the supervisor decides how to handle recovery
26
- link(@supervisor.actors.last)
28
+ @supervisor = Worker.supervise(as: Worker.handle(topic, subscriber), args: [topic, subscriber, proc])
27
29
  end
28
30
  end
29
31
 
30
32
  # When we run all the workers as actors in their own threads. This run also blocks to make sure
31
33
  # the spawned threads remain operational indefinitely
32
34
  def run
33
- @supervisor.actors.each { |w| w.async.run }
34
- # Put the supervisor thread to sleep indefinitely # Better way?
35
+ # Put the supervisor thread to sleep indefinitely
35
36
  loop do
36
- # TODO: Better way?
37
- sleep(5)
37
+ # TODO: Perhaps there is a better way?
38
+ sleep(60)
39
+ end
40
+ end
41
+
42
+ # This callback is fired when the worker signals it is ready to commence work after initialisation or
43
+ # recommence after recovering from a failure.
44
+ # When a worker completes initialisation it can take a while for the worker to be registered as an Actor
45
+ # in Celluloid, for this reason we need need to put a minor delay in the initialisation procedure
46
+ def worker_ready(*args)
47
+ info("Worker bootstrapping with #{args}...")
48
+ sleep(ENV['ACTOR_BOOTSTRAP_DELAY'] || 2) # TODO: Perhaps there is a better way?
49
+ worker = get_worker(args[1], args[2])
50
+ if worker
51
+ # Link the worker to the supervisor so if the worker misbehaves the supervisor is alerted
52
+ # to this poor behaviour, the supervisor decides how to handle recovery
53
+ link(worker)
54
+ worker.async.run
55
+ else
56
+ error("Worker bootstrap failure with #{args}")
38
57
  end
39
58
  end
40
59
 
41
60
  private
42
61
 
62
+ # Retrieve a worker through the supervisory structure, this can take a while as the worker might
63
+ # be going through a restart procedure by the actor framework
64
+ def get_worker(topic, subscriber)
65
+ handle = Worker.handle(topic, subscriber)
66
+ Celluloid::Actor[handle.to_sym]
67
+ end
68
+
43
69
  # This callback function fires when an worker dies
44
70
  def worker_died(worker, reason)
45
- # TODO: Log this instead
46
- puts "#{worker.inspect} has died: #{reason.class}"
71
+ error("Worker #{worker.inspect} has died: #{reason.class}")
47
72
  end
48
73
  end
49
74
  end
@@ -1,15 +1,15 @@
1
1
  # Major.Minor.Patch version numbering
2
2
  module Bifrost
3
- # The major version of Sif, updated only for major changes that are
3
+ # The major version of Bifrost, updated only for major changes that are
4
4
  # likely to require modification to Filmpond apps.
5
5
  MAJOR_VERSION = 0
6
6
 
7
- # The minor version of Sif, updated for new feature releases.
7
+ # The minor version of Bifrost, updated for new feature releases.
8
8
  MINOR_VERSION = 1
9
9
 
10
- # The patch version of Sif, updated only for bug fixes from the last
10
+ # The patch version of Bifrost, updated only for bug fixes from the last
11
11
  # feature release.
12
- PATCH_VERSION = 0
12
+ PATCH_VERSION = 1
13
13
 
14
14
  # The full version as a string.
15
15
  VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}.#{PATCH_VERSION}".freeze
@@ -9,20 +9,26 @@ module Bifrost
9
9
  # combination one at a time
10
10
  class Worker < Bifrost::Entity
11
11
  include Celluloid
12
+ include Celluloid::Internals::Logger
13
+ include Celluloid::Notifications
12
14
 
13
- attr_reader :topic_name, :subscriber_name, :callback
15
+ attr_reader :topic, :subscriber, :callback
14
16
 
15
- def initialize(topic_name, subscriber_name, callback)
16
- raise Bifrost::Exceptions::UnsupportedLambdaError, 'not a proc' unless callback.respond_to?(:call)
17
- @topic_name ||= topic_name
18
- @subscriber_name ||= subscriber_name
17
+ # Initialise the worker/actor. This actually starts the worker by implicitly calling the run method
18
+ def initialize(topic, subscriber, callback)
19
+ raise Bifrost::Exceptions::UnsupportedLambdaError, 'callback is not a proc' unless callback.respond_to?(:call)
20
+ @topic ||= topic
21
+ @subscriber ||= subscriber
19
22
  @callback ||= callback
20
23
  super()
24
+ info("Worker #{to_sym} starting up...")
25
+ publish('worker_ready', topic, subscriber)
21
26
  end
22
27
 
23
28
  # This method starts the actor, which runs in an infinite loop. This means the worker should
24
29
  # not terminate, but if it does, the supervisor will make sure it restarts
25
30
  def run
31
+ info("Worker #{to_sym} running...")
26
32
  loop do
27
33
  read_message
28
34
  sleep(ENV['QUEUE_DELAY'] || 10)
@@ -32,7 +38,7 @@ module Bifrost
32
38
  # Workers have a friendly name which is a combination of the topic and subscriber name
33
39
  # which in the operational environment should be unique
34
40
  def to_s
35
- Worker.supervisor_handle(topic_name, subscriber_name)
41
+ Worker.handle(topic, subscriber)
36
42
  end
37
43
 
38
44
  # Utlity method to get the name of the worker as a symbol
@@ -41,15 +47,15 @@ module Bifrost
41
47
  end
42
48
 
43
49
  # A worker can tell you what it's friendly name will be, this is in order for supervision
44
- def self.supervisor_handle(topic_name, subscriber_name)
45
- "#{topic_name}-#{subscriber_name}"
50
+ def self.handle(topic, subscriber)
51
+ "#{topic.downcase}#{subscriber.downcase}"
46
52
  end
47
53
 
48
54
  private
49
55
 
50
56
  # Actual processing of the message
51
57
  def read_message
52
- message = bus.receive_subscription_message(topic_name, subscriber_name, timeout: ENV['TIMEOUT'] || 10)
58
+ message = bus.receive_subscription_message(topic, subscriber, timeout: ENV['TIMEOUT'] || 10)
53
59
  if message
54
60
  callback.call(message.properties['message'])
55
61
  bus.delete_subscription_message(message)
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'bifrost'
3
3
 
4
4
  describe Bifrost::Manager do
5
- let(:cb ) { proc { |m| puts "Principle Received: message #{m}" } }
5
+ let(:cb) { proc { |m| puts "Principle Received: message #{m}" } }
6
6
  let(:worker) { Bifrost::Worker.new('topic', 'subscriber', proc) }
7
7
  let(:manager) { Bifrost::Manager.new }
8
8
 
@@ -83,7 +83,7 @@ describe Bifrost::Topic do
83
83
  end
84
84
 
85
85
  it 'should not accept names with spaces in them' do
86
- invalid_topic_name = Bifrost::Topic.new('topic name')
87
- expect { invalid_topic_name.save }.to raise_error(URI::InvalidURIError)
86
+ invalid_topic = Bifrost::Topic.new('topic name')
87
+ expect { invalid_topic.save }.to raise_error(URI::InvalidURIError)
88
88
  end
89
89
  end
@@ -9,8 +9,8 @@ describe Bifrost::Worker do
9
9
  let(:cb) { proc { |m| puts "Received: message #{m}" } }
10
10
  subject(:worker) { Bifrost::Worker.new('topic', 'subscriber', cb) }
11
11
 
12
- it { is_expected.to respond_to(:topic_name) }
13
- it { is_expected.to respond_to(:subscriber_name) }
12
+ it { is_expected.to respond_to(:topic) }
13
+ it { is_expected.to respond_to(:subscriber) }
14
14
 
15
15
  it 'should not except non procs in last argument' do
16
16
  expect { Bifrost::Worker.new('topic', 'subscriber', 'x') }
@@ -18,7 +18,12 @@ describe Bifrost::Worker do
18
18
  end
19
19
 
20
20
  it 'should have a friendly string name' do
21
- expect(worker.to_s).to eq("#{worker.topic_name}-#{worker.subscriber_name}")
21
+ expect(worker.to_s).to eq("#{worker.topic}#{worker.subscriber}")
22
+ end
23
+
24
+ it 'should downcase the friendly name' do
25
+ another_worker = Bifrost::Worker.new('toPic', 'subScriber', cb)
26
+ expect(another_worker.to_s).to eq("#{another_worker.topic.downcase}#{another_worker.subscriber.downcase}")
22
27
  end
23
28
 
24
29
  it 'should have a friendly symbol name' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bi-frost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shirren Premaratne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-31 00:00:00.000000000 Z
11
+ date: 2016-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: azure
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: rubocop
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
@@ -150,8 +150,8 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0.7'
153
- description: Topic definitions should occur via the Bifrost. Subscriptions should
154
- take place via the Bifrost. Therefore all messages need to transit through the Bifrost
153
+ description: Bifrost is a pub/sub wrapper library which uses Azure message bus and
154
+ actors.
155
155
  email:
156
156
  - shirren@filmpond.com
157
157
  executables: []
@@ -178,7 +178,8 @@ files:
178
178
  - spec/bifrost/worker_spec.rb
179
179
  - spec/spec_helper.rb
180
180
  homepage: https://github.com/filmpond/bifrost
181
- licenses: []
181
+ licenses:
182
+ - MIT
182
183
  metadata: {}
183
184
  post_install_message:
184
185
  rdoc_options: []
@@ -188,7 +189,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
189
  requirements:
189
190
  - - ">="
190
191
  - !ruby/object:Gem::Version
191
- version: '0'
192
+ version: '2.0'
192
193
  required_rubygems_version: !ruby/object:Gem::Requirement
193
194
  requirements:
194
195
  - - ">="
@@ -199,7 +200,8 @@ rubyforge_project:
199
200
  rubygems_version: 2.5.1
200
201
  signing_key:
201
202
  specification_version: 4
202
- summary: Bifrost is a simple pub/sub messaging wrapper component.
203
+ summary: Bifrost is a pub/sub wrapper library which uses the Azure message bus and
204
+ actors.
203
205
  test_files:
204
206
  - spec/bifrost/manager_spec.rb
205
207
  - spec/bifrost/message_spec.rb