Skip to content

Commit 6903510

Browse files
authored
Queue and multi fiber (#5)
* Changed to fiber safe approach that supports queue of events * Forgot some things
1 parent d236bef commit 6903510

8 files changed

Lines changed: 328 additions & 207 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ Spectrum.dispatch_async_event(event_one, :my_queue)
7474
event_two = FooBarTwoEvent.new(id: 2)
7575
Spectrum.dispatch_async_event(event_two, :my_queue)
7676
Spectrum::EventQueue.stop(:my_queue)
77+
78+
## Advanced Queue Settings
79+
Spectrum::EventQueue.start(
80+
name: :my_queue,
81+
number_of_workers: 10
82+
queue_size: 10
83+
)
7784
```
7885

7986
## Contributing

shard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: spectrum
2-
version: 0.1.0
2+
version: 0.2.0
33

44
authors:
55
- Tom Elliot <telliot16@gmail.com>

spec/event_spec.cr

Lines changed: 95 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,95 @@
1-
require "./spec_helper"
2-
include Spectrum
3-
describe Spectrum do
4-
it "should have only events that are listening to an event recieve it" do
5-
event_one = FooBarOneEvent.new(id: 1)
6-
event_two = FooBarTwoEvent.new(id: 2)
7-
event_three = FooBarOneEvent.new(id: 3)
8-
9-
Spectrum.dispatch_sync_event(event_one)
10-
Spectrum.dispatch_sync_event(event_two)
11-
Spectrum.dispatch_sync_event(event_three)
12-
13-
event_one.handlers.size.should eq(2)
14-
event_two.handlers.size.should eq(2)
15-
event_three.handlers.size.should eq(2)
16-
end
17-
18-
it "async events should be triggered" do
19-
event_queue = EventQueue.start(:test)
20-
event_one = FooBarOneEvent.new(id: 1)
21-
event_two = FooBarTwoEvent.new(id: 2)
22-
event_three = FooBarOneEvent.new(id: 3)
23-
24-
Spectrum.dispatch_async_event(event_one, :test)
25-
Spectrum.dispatch_async_event(event_two, :test)
26-
Spectrum.dispatch_async_event(event_three, :test)
27-
while event_queue.busy?
28-
# This is just a loop to ensure there is not a race condition
29-
end
30-
event_one.handlers.size.should eq(2)
31-
event_two.handlers.size.should eq(2)
32-
event_three.handlers.size.should eq(2)
33-
EventQueue.stop(:test)
34-
end
35-
end
1+
require "./spec_helper"
2+
include Spectrum
3+
describe Spectrum do
4+
it "should have only events that are listening to an event recieve it" do
5+
event_one = FooBarOneEvent.new(id: 1)
6+
event_two = FooBarTwoEvent.new(id: 2)
7+
event_three = FooBarOneEvent.new(id: 3)
8+
9+
Spectrum.dispatch_sync_event(event_one)
10+
Spectrum.dispatch_sync_event(event_two)
11+
Spectrum.dispatch_sync_event(event_three)
12+
13+
event_one.handlers.size.should eq(2)
14+
event_two.handlers.size.should eq(2)
15+
event_three.handlers.size.should eq(2)
16+
end
17+
18+
it "async events should be triggered" do
19+
event_queue = EventQueue.start(:test)
20+
event_one = FooBarOneEvent.new(id: 1)
21+
event_two = FooBarTwoEvent.new(id: 2)
22+
event_three = FooBarOneEvent.new(id: 3)
23+
24+
Spectrum.dispatch_async_event(event_one, :test)
25+
Spectrum.dispatch_async_event(event_two, :test)
26+
Spectrum.dispatch_async_event(event_three, :test)
27+
28+
Fiber.yield
29+
30+
event_one.handlers.size.should eq(2)
31+
event_two.handlers.size.should eq(2)
32+
event_three.handlers.size.should eq(2)
33+
EventQueue.stop(:test)
34+
end
35+
36+
it "async events should be none blocking for the caller" do
37+
event_queue1 = EventQueue.start(:test1)
38+
event_queue2 = EventQueue.start(:test2)
39+
event1 = LockEvent.new
40+
event2 = LockEvent.new
41+
Spectrum.dispatch_async_event(event1, :test1)
42+
Spectrum.dispatch_async_event(event1, :test1)
43+
Spectrum.dispatch_async_event(event2, :test2)
44+
Spectrum.dispatch_async_event(event2, :test2)
45+
Fiber.yield
46+
event1.unlock!
47+
event2.unlock!
48+
Fiber.yield
49+
event1.unlock!
50+
event2.unlock!
51+
EventQueue.stop(:test1)
52+
EventQueue.stop(:test2)
53+
end
54+
55+
it "async events should queue" do
56+
event_queue = EventQueue.start(name: :test, number_of_workers: 1, queue_size: 2)
57+
event1 = LockEvent.new
58+
event2 = LockEvent.new
59+
event3 = LockEvent.new
60+
Spectrum.dispatch_async_event(event1, :test)
61+
Spectrum.dispatch_async_event(event2, :test)
62+
Spectrum.dispatch_async_event(event3, :test)
63+
Fiber.yield
64+
event1.unlock!
65+
event2.unlock!
66+
event3.unlock!
67+
Fiber.yield
68+
event1.unlock!
69+
event2.unlock!
70+
event3.unlock!
71+
EventQueue.stop(:test)
72+
end
73+
74+
it "async events should queue hit error if queue is full and timeout is hit" do
75+
event_queue = EventQueue.start(name: :test, number_of_workers: 1, queue_size: 1, queue_timeout: 0)
76+
event1 = LockEvent.new
77+
event2 = LockEvent.new
78+
event3 = LockEvent.new
79+
Spectrum.dispatch_async_event(event1, :test)
80+
Fiber.yield
81+
Spectrum.dispatch_async_event(event2, :test)
82+
Fiber.yield
83+
error = nil
84+
begin
85+
Spectrum.dispatch_async_event(event3, :test)
86+
rescue e : Spectrum::EventQueue::FullException
87+
error = e
88+
end
89+
event1.unlock!
90+
event2.unlock!
91+
event3.unlock!
92+
error.class.should eq(Spectrum::EventQueue::FullException)
93+
EventQueue.stop(:test)
94+
end
95+
end

spec/spec_helper.cr

Lines changed: 85 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,85 @@
1-
require "spec"
2-
require "../src/spectrum"
3-
4-
class FooBarOneEvent
5-
include Spectrum::Event
6-
getter :handlers
7-
def initialize(@id : Int32)
8-
@handlers = [] of Spectrum::EventHandler
9-
end
10-
11-
def store_handler(handler : Spectrum::EventHandler)
12-
@handlers << handler
13-
end
14-
end
15-
16-
class FooBarTwoEvent
17-
include Spectrum::Event
18-
getter :handlers
19-
def initialize(@id : Int32)
20-
@handlers = [] of Spectrum::EventHandler
21-
end
22-
23-
def store_handler(handler : Spectrum::EventHandler)
24-
@handlers << handler
25-
end
26-
end
27-
28-
class FooBarOneEventHandler
29-
include Spectrum::EventHandler
30-
Syringe.injectable
31-
32-
def on_event(event : FooBarOneEvent)
33-
event.store_handler(self)
34-
end
35-
end
36-
37-
class FooBarTwoEventHandler
38-
include Spectrum::EventHandler
39-
Syringe.injectable
40-
41-
def on_event(event : FooBarTwoEvent)
42-
event.store_handler(self)
43-
end
44-
end
45-
46-
class FooBarBothEventHandler
47-
include Spectrum::EventHandler
48-
Syringe.injectable
49-
50-
def on_event(event : FooBarOneEvent)
51-
event.store_handler(self)
52-
end
53-
54-
def on_event(event : FooBarTwoEvent)
55-
event.store_handler(self)
56-
end
57-
end
1+
require "spec"
2+
require "../src/spectrum"
3+
4+
class FooBarOneEvent
5+
include Spectrum::Event
6+
getter :handlers
7+
def initialize(@id : Int32)
8+
@handlers = [] of Spectrum::EventHandler
9+
end
10+
11+
def store_handler(handler : Spectrum::EventHandler)
12+
@handlers << handler
13+
end
14+
end
15+
16+
class FooBarTwoEvent
17+
include Spectrum::Event
18+
getter :handlers
19+
def initialize(@id : Int32)
20+
@handlers = [] of Spectrum::EventHandler
21+
end
22+
23+
def store_handler(handler : Spectrum::EventHandler)
24+
@handlers << handler
25+
end
26+
end
27+
28+
class FooBarOneEventHandler
29+
include Spectrum::EventHandler
30+
Syringe.injectable
31+
32+
def on_event(event : FooBarOneEvent)
33+
event.store_handler(self)
34+
end
35+
end
36+
37+
class FooBarTwoEventHandler
38+
include Spectrum::EventHandler
39+
Syringe.injectable
40+
41+
def on_event(event : FooBarTwoEvent)
42+
event.store_handler(self)
43+
end
44+
end
45+
46+
class FooBarBothEventHandler
47+
include Spectrum::EventHandler
48+
Syringe.injectable
49+
50+
def on_event(event : FooBarOneEvent)
51+
event.store_handler(self)
52+
end
53+
54+
def on_event(event : FooBarTwoEvent)
55+
event.store_handler(self)
56+
end
57+
end
58+
59+
class LockEvent
60+
include Spectrum::Event
61+
getter :lock
62+
def initialize
63+
@lock = false
64+
end
65+
66+
def lock!
67+
@lock = true
68+
end
69+
70+
def unlock!
71+
@lock = false
72+
end
73+
end
74+
75+
class LockEventHandler
76+
include Spectrum::EventHandler
77+
Syringe.injectable
78+
79+
def on_event(event : LockEvent)
80+
event.lock!
81+
while event.lock
82+
Fiber.yield
83+
end
84+
end
85+
end

src/spectrum/event_dispatcher.cr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
module Spectrum
2-
class EventDispatcher
3-
def dispatch_sync_event(event : Event)
4-
listeners = EventHandlers.new
5-
listeners.on_event(event)
6-
end
7-
8-
def dispatch_async_event(event : Event, queue_name : Symbol)
9-
event_queue = EventQueue.get(queue_name)
10-
event_queue.send(event)
11-
end
12-
end
1+
module Spectrum
2+
class EventDispatcher
3+
def dispatch_sync_event(event : Event)
4+
listeners = EventHandlers.new
5+
listeners.on_event(event)
6+
end
7+
8+
def dispatch_async_event(event : Event, queue_name : Symbol)
9+
event_queue = EventQueue.get(queue_name)
10+
event_queue.send(event)
11+
end
12+
end
1313
end

src/spectrum/event_handler.cr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
module Spectrum
2-
module EventHandler
3-
def on_event(event : Event)
4-
# This is just a hook that is overloaded
5-
end
6-
end
1+
module Spectrum
2+
module EventHandler
3+
def on_event(event : Event)
4+
# This is just a hook that is overloaded
5+
end
6+
end
77
end

src/spectrum/event_handlers.cr

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
require "syringe"
2-
module Spectrum
3-
class EventHandlers
4-
include Syringe
5-
Syringe.injectable
6-
7-
def initialize(@handlers : Array(EventHandler))
8-
end
9-
10-
def on_event(event : Event)
11-
@handlers.each do |handler|
12-
handler.on_event(event)
13-
end
14-
end
15-
end
1+
require "syringe"
2+
module Spectrum
3+
class EventHandlers
4+
include Syringe
5+
Syringe.injectable
6+
7+
def initialize(@handlers : Array(EventHandler))
8+
end
9+
10+
def on_event(event : Event)
11+
@handlers.each do |handler|
12+
handler.on_event(event)
13+
end
14+
end
15+
end
1616
end

0 commit comments

Comments
 (0)