asir 0.2.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.
Files changed (121) hide show
  1. data/.gitignore +11 -0
  2. data/Gemfile +16 -0
  3. data/README.textile +50 -0
  4. data/Rakefile +83 -0
  5. data/VERSION +1 -0
  6. data/asir.gemspec +36 -0
  7. data/asir.riterate.yml +114 -0
  8. data/bin/asir +6 -0
  9. data/doc/Rakefile +8 -0
  10. data/doc/asir-sequence.pic +84 -0
  11. data/doc/asir-sequence.svg +1559 -0
  12. data/doc/sequence.pic +430 -0
  13. data/example/asir_control.sh +24 -0
  14. data/example/asir_control_client_http.rb +14 -0
  15. data/example/asir_control_client_zmq.rb +15 -0
  16. data/example/config/asir_config.rb +63 -0
  17. data/example/delayed_service.rb +15 -0
  18. data/example/ex01.rb +12 -0
  19. data/example/ex02.rb +12 -0
  20. data/example/ex03.rb +19 -0
  21. data/example/ex04.rb +33 -0
  22. data/example/ex05.rb +16 -0
  23. data/example/ex06.rb +26 -0
  24. data/example/ex07.rb +28 -0
  25. data/example/ex08.rb +30 -0
  26. data/example/ex09.rb +25 -0
  27. data/example/ex10.rb +24 -0
  28. data/example/ex11.rb +48 -0
  29. data/example/ex12.rb +34 -0
  30. data/example/ex13.rb +35 -0
  31. data/example/ex14.rb +30 -0
  32. data/example/ex15.rb +13 -0
  33. data/example/ex16.rb +33 -0
  34. data/example/ex17.rb +41 -0
  35. data/example/ex18.rb +62 -0
  36. data/example/ex19.rb +32 -0
  37. data/example/ex20.rb +28 -0
  38. data/example/ex21.rb +28 -0
  39. data/example/ex22.rb +15 -0
  40. data/example/ex23.rb +20 -0
  41. data/example/ex24.rb +35 -0
  42. data/example/example_helper.rb +51 -0
  43. data/example/sample_service.rb +162 -0
  44. data/example/unsafe_service.rb +12 -0
  45. data/hack_night/README.txt +18 -0
  46. data/hack_night/exercise/prob-1.rb +18 -0
  47. data/hack_night/exercise/prob-2.rb +21 -0
  48. data/hack_night/exercise/prob-3.rb +16 -0
  49. data/hack_night/exercise/prob-4.rb +36 -0
  50. data/hack_night/exercise/prob-5.rb +36 -0
  51. data/hack_night/exercise/prob-6.rb +95 -0
  52. data/hack_night/exercise/prob-7.rb +34 -0
  53. data/hack_night/solution/math_service.rb +11 -0
  54. data/hack_night/solution/prob-1.rb +12 -0
  55. data/hack_night/solution/prob-2.rb +15 -0
  56. data/hack_night/solution/prob-3.rb +17 -0
  57. data/hack_night/solution/prob-4.rb +37 -0
  58. data/hack_night/solution/prob-5.rb +21 -0
  59. data/hack_night/solution/prob-6.rb +33 -0
  60. data/hack_night/solution/prob-7.rb +36 -0
  61. data/lab/phony_proc.rb +31 -0
  62. data/lib/asir.rb +253 -0
  63. data/lib/asir/additional_data.rb +25 -0
  64. data/lib/asir/channel.rb +130 -0
  65. data/lib/asir/client.rb +111 -0
  66. data/lib/asir/code_block.rb +57 -0
  67. data/lib/asir/code_more.rb +50 -0
  68. data/lib/asir/coder.rb +26 -0
  69. data/lib/asir/coder/base64.rb +19 -0
  70. data/lib/asir/coder/chain.rb +30 -0
  71. data/lib/asir/coder/identity.rb +23 -0
  72. data/lib/asir/coder/json.rb +30 -0
  73. data/lib/asir/coder/marshal.rb +17 -0
  74. data/lib/asir/coder/null.rb +23 -0
  75. data/lib/asir/coder/proc.rb +22 -0
  76. data/lib/asir/coder/sign.rb +48 -0
  77. data/lib/asir/coder/xml.rb +213 -0
  78. data/lib/asir/coder/yaml.rb +33 -0
  79. data/lib/asir/coder/zlib.rb +21 -0
  80. data/lib/asir/configuration.rb +32 -0
  81. data/lib/asir/error.rb +34 -0
  82. data/lib/asir/identity.rb +36 -0
  83. data/lib/asir/initialization.rb +23 -0
  84. data/lib/asir/log.rb +82 -0
  85. data/lib/asir/main.rb +396 -0
  86. data/lib/asir/message.rb +31 -0
  87. data/lib/asir/message/delay.rb +35 -0
  88. data/lib/asir/object_resolving.rb +15 -0
  89. data/lib/asir/result.rb +39 -0
  90. data/lib/asir/retry_behavior.rb +54 -0
  91. data/lib/asir/transport.rb +241 -0
  92. data/lib/asir/transport/beanstalk.rb +217 -0
  93. data/lib/asir/transport/broadcast.rb +34 -0
  94. data/lib/asir/transport/buffer.rb +115 -0
  95. data/lib/asir/transport/composite.rb +19 -0
  96. data/lib/asir/transport/connection_oriented.rb +180 -0
  97. data/lib/asir/transport/delay.rb +38 -0
  98. data/lib/asir/transport/delegation.rb +53 -0
  99. data/lib/asir/transport/fallback.rb +36 -0
  100. data/lib/asir/transport/file.rb +88 -0
  101. data/lib/asir/transport/http.rb +54 -0
  102. data/lib/asir/transport/local.rb +21 -0
  103. data/lib/asir/transport/null.rb +14 -0
  104. data/lib/asir/transport/payload_io.rb +52 -0
  105. data/lib/asir/transport/rack.rb +73 -0
  106. data/lib/asir/transport/retry.rb +41 -0
  107. data/lib/asir/transport/stream.rb +35 -0
  108. data/lib/asir/transport/subprocess.rb +30 -0
  109. data/lib/asir/transport/tcp_socket.rb +34 -0
  110. data/lib/asir/transport/webrick.rb +50 -0
  111. data/lib/asir/transport/zmq.rb +110 -0
  112. data/lib/asir/uuid.rb +32 -0
  113. data/lib/asir/version.rb +3 -0
  114. data/spec/const_get_speed_spec.rb +33 -0
  115. data/spec/debug_helper.rb +20 -0
  116. data/spec/example_spec.rb +88 -0
  117. data/spec/json_spec.rb +128 -0
  118. data/spec/spec_helper.rb +3 -0
  119. data/spec/xml_spec.rb +144 -0
  120. data/stylesheets/slides.css +105 -0
  121. metadata +173 -0
@@ -0,0 +1,34 @@
1
+ require 'asir/transport/composite'
2
+
3
+ module ASIR
4
+ class Transport
5
+ # !SLIDE
6
+ # Broadcast Transport
7
+ #
8
+ # Broadcast to multiple Transports.
9
+ class Broadcast < self
10
+ include Composite
11
+
12
+ def _send_message message, message_payload
13
+ result = first_exception = nil
14
+ transports.each do | transport |
15
+ begin
16
+ result = transport.send_message(message)
17
+ rescue ::Exception => exc
18
+ first_exception ||= exc
19
+ _handle_send_message_exception! transport, message, exc
20
+ raise unless @continue_on_exception
21
+ end
22
+ end
23
+ if first_exception && @reraise_first_exception
24
+ $! = first_exception
25
+ raise
26
+ end
27
+ result
28
+ end
29
+
30
+ end
31
+ # !SLIDE END
32
+ end
33
+ end
34
+
@@ -0,0 +1,115 @@
1
+ require 'asir/transport'
2
+ require 'thread'
3
+
4
+ module ASIR
5
+ class Transport
6
+ # !SLIDE
7
+ # Buffer Transport
8
+ #
9
+ # Buffers Messages until #flush!
10
+ # Assumes One-way Messages.
11
+ class Buffer < self
12
+ include Delegation
13
+
14
+ # Transport to send_message.
15
+ attr_accessor :transport
16
+
17
+ def initialize *args
18
+ super
19
+ @messages = Queue.new
20
+ @messages_mutex = Mutex.new
21
+ @paused = 0
22
+ @paused_mutex = Mutex.new
23
+ end
24
+
25
+ # If paused, queue messages,
26
+ # Otherwise delegate immediately to #transport.
27
+ def _send_message message, message_payload
28
+ return nil if @ignore
29
+ if paused?
30
+ @messages_mutex.synchronize do
31
+ @messages << message
32
+ end
33
+ nil
34
+ else
35
+ @transport.send_message(message)
36
+ end
37
+ end
38
+
39
+ # Returns true if currently paused.
40
+ # Messages are queued until #resume!.
41
+ def paused?
42
+ @paused > 0
43
+ end
44
+
45
+ # Pauses all messages until resume!.
46
+ # May be called multiple times.
47
+ def pause!
48
+ @paused_mutex.synchronize do
49
+ @paused += 1
50
+ end
51
+ self
52
+ end
53
+
54
+ # Will automatically call #flush! when not #paused?.
55
+ def resume!
56
+ should_flush = @paused_mutex.synchronize do
57
+ @paused -= 1 if @paused > 0
58
+ @paused == 0
59
+ end
60
+ flush! if should_flush
61
+ self
62
+ end
63
+
64
+ def size
65
+ @messages_mutex.synchronize do
66
+ @messages.size
67
+ end
68
+ end
69
+
70
+ # Will flush pending Messages even if ! #paused?.
71
+ def flush!
72
+ clear!.each do | message |
73
+ @transport.send_message(message)
74
+ end
75
+ self
76
+ end
77
+
78
+ # Clear all pending Messages without sending them.
79
+ # Returns Array of Messages that would have been sent.
80
+ def clear!
81
+ messages = [ ]
82
+ @messages_mutex.synchronize do
83
+ @messages.size.times do
84
+ messages << @messages.shift(true)
85
+ end
86
+ end
87
+ messages
88
+ end
89
+
90
+ # Take Message from head of Queue.
91
+ def shift non_block=false
92
+ @messages.shift(non_block)
93
+ end
94
+
95
+ # Processes queue.
96
+ # Usually used in worker Thread.
97
+ def process! non_block=false
98
+ @running = true
99
+ while @running && message = shift(non_block)
100
+ @transport.send_message(message)
101
+ end
102
+ message
103
+ end
104
+
105
+ # Stop processing queue.
106
+ def stop!
107
+ @messages_mutex.synchronize do
108
+ @ignore = true; @running = false
109
+ end
110
+ self
111
+ end
112
+ end
113
+ # !SLIDE END
114
+ end
115
+ end
@@ -0,0 +1,19 @@
1
+ require 'asir/transport/delegation'
2
+ module ASIR
3
+ class Transport
4
+ # !SLIDE
5
+ # A Transport composed of other Transports.
6
+ #
7
+ # Classes that mix this in should define #_send_message(message, message_payload).
8
+ module Composite
9
+ include Delegation
10
+
11
+ # Enumerable of Transport objects.
12
+ attr_accessor :transports
13
+ # If true, continue with other Transports when Transport#send_message raises an Exception.
14
+ attr_accessor :continue_on_exception
15
+ end
16
+ # !SLIDE END
17
+ end
18
+ end
19
+
@@ -0,0 +1,180 @@
1
+ require 'asir/transport/stream'
2
+ require 'asir/transport/payload_io'
3
+ require 'uri'
4
+
5
+ module ASIR
6
+ class Transport
7
+ # !SLIDE
8
+ # Connection-Oriented Transport
9
+ class ConnectionOriented < Stream
10
+ include PayloadIO
11
+
12
+ attr_accessor :uri, :scheme, :port, :address
13
+ alias :protocol :scheme
14
+ alias :protocol= :scheme=
15
+
16
+ def uri
17
+ @uri ||= "#{scheme}://#{address}:#{port}"
18
+ end
19
+
20
+ def scheme
21
+ @scheme ||=
22
+ case
23
+ when @uri
24
+ URI.parse(@uri).scheme
25
+ else
26
+ 'tcp'.freeze
27
+ end
28
+ end
29
+
30
+ def address
31
+ @address ||=
32
+ case
33
+ when @uri
34
+ URI.parse(@uri).host
35
+ else
36
+ '127.0.0.1'.freeze
37
+ end
38
+ end
39
+
40
+ def port
41
+ @port ||=
42
+ case
43
+ when @uri
44
+ URI.parse(@uri).port
45
+ else
46
+ raise Error, "#{self.class}: port not set."
47
+ end
48
+ end
49
+
50
+ # !SLIDE
51
+ # Returns a connected Channel.
52
+ def stream
53
+ @stream ||=
54
+ connect!
55
+ end
56
+
57
+ # Yields Channel after _connect!.
58
+ def connect!(opts = nil, &blk)
59
+ base_opts = {
60
+ :on_connect => lambda { | channel |
61
+ connection = _connect!
62
+ blk.call(connection) if blk
63
+ connection
64
+ }
65
+ }
66
+ base_opts.update(opts) if opts
67
+ Channel.new(base_opts)
68
+ end
69
+
70
+ # Returns raw client stream.
71
+ def _connect!
72
+ _log { "_connect! #{uri}" } if @verbose >= 1
73
+ sock = _client_connect!
74
+ _log { "_connect! socket=#{sock}" } if @verbose >= 1
75
+ _after_connect! sock
76
+ sock
77
+ rescue ::Exception => err
78
+ raise Error, "Cannot connect to #{self.class} #{uri}: #{err.inspect}", err.backtrace
79
+ end
80
+
81
+ # Subclasses can override.
82
+ def _after_connect! stream
83
+ self
84
+ end
85
+
86
+ # Subclasses can override.
87
+ def _before_close! stream
88
+ self
89
+ end
90
+
91
+ # !SLIDE
92
+ # Sends the encoded Message payload String.
93
+ def _send_message message, message_payload
94
+ stream.with_stream! do | io |
95
+ _write message_payload, io
96
+ end
97
+ end
98
+
99
+ # !SLIDE
100
+ # Receives the encoded Message payload String.
101
+ def _receive_message stream, additional_data
102
+ [ _read(stream), nil ]
103
+ end
104
+
105
+ # !SLIDE
106
+ # Sends the encoded Result payload String.
107
+ def _send_result message, result, result_payload, stream, message_state
108
+ unless @one_way || message.one_way
109
+ _write result_payload, stream
110
+ end
111
+ end
112
+
113
+ # !SLIDE
114
+ # Receives the encoded Result payload String.
115
+ def _receive_result message, opaque_result
116
+ unless @one_way || message.one_way
117
+ stream.with_stream! do | io |
118
+ _read io
119
+ end
120
+ end
121
+ end
122
+
123
+ # !SLIDE
124
+ # Server
125
+
126
+ def prepare_server!
127
+ _log { "prepare_server! #{uri}" } if @verbose >= 1
128
+ _server!
129
+ rescue ::Exception => err
130
+ _log [ "prepare_server! #{uri}", :exception, err ]
131
+ raise Error, "Cannot prepare server on #{self.class} #{uri}: #{err.inspect}", err.backtrace
132
+ end
133
+
134
+ def run_server!
135
+ _log { "run_server! #{uri}" } if @verbose >= 1
136
+ with_server_signals! do
137
+ @running = true
138
+ while @running
139
+ stream = _server_accept_connection! @server
140
+ _log { "run_server!: connected" } if @verbose >= 1
141
+ begin
142
+ # Same socket for both in and out stream.
143
+ serve_stream! stream, stream
144
+ ensure
145
+ _server_close_connection!(stream)
146
+ end
147
+ _log { "run_server!: disconnected" } if @verbose >= 1
148
+ end
149
+ end
150
+ self
151
+ ensure
152
+ _server_close!
153
+ end
154
+
155
+ def _server!
156
+ raise Error::SubclassResponsibility, "_server!"
157
+ end
158
+
159
+ def _server_close!
160
+ if @server
161
+ @server.close rescue nil
162
+ end
163
+ @server = nil
164
+ self
165
+ end
166
+
167
+ # Accept a client connection.
168
+ def _server_accept_connection! server
169
+ raise Error::SubclassResponsibility, "_server_accept_connection!"
170
+ end
171
+
172
+ # Close a client connection.
173
+ def _server_close_connection! stream
174
+ raise Error::SubclassResponsibility, "_server_close_connection!"
175
+ end
176
+ end
177
+ # !SLIDE END
178
+ end # class
179
+ end # module
180
+
@@ -0,0 +1,38 @@
1
+ module ASIR
2
+ class Message
3
+ # !SLIDE
4
+ # Message Delay Support
5
+ #
6
+ module Delay
7
+ # Returns the number of seconds from now, that the message should be delayed.
8
+ # If message.delay is Numeric, sets message.delay to the Time to delay til.
9
+ # If message.delay is Time, returns (now - message.delay).to_f
10
+ # Returns Float if message.delay was set, or nil.
11
+ # Returns 0 if delay has already expired.
12
+ def relative_message_delay! message, now = nil
13
+ case delay = message.delay
14
+ when nil
15
+ when Numeric
16
+ now ||= Time.now
17
+ delay = delay.to_f
18
+ message.delay = (now + delay).utc
19
+ when Time
20
+ now ||= Time.now
21
+ delay = (delay - now).to_f
22
+ delay = 0 if delay < 0
23
+ else
24
+ raise TypeError, "Expected message.delay to be Numeric or Time, given #{delay.class}"
25
+ end
26
+ delay
27
+ end
28
+
29
+ def wait_for_delay! message
30
+ while (delay = relative_message_delay!(message)) && delay > 0
31
+ sleep delay
32
+ end
33
+ self
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,53 @@
1
+ module ASIR
2
+ class Transport
3
+ # !SLIDE
4
+ # A Transport that delgated to one or more other Transports.
5
+ #
6
+ # Classes that include this must define #_send_message(message, message_payload).
7
+ module Delegation
8
+ # If true, reraise the first Exception that occurred during Transport#send_message.
9
+ attr_accessor :reraise_first_exception
10
+
11
+ # Proc to call(transport, message, exc) when a delegated #send_message fails.
12
+ attr_accessor :on_send_message_exception
13
+
14
+ # Proc to call(transport, message) when #send_message fails with no recourse.
15
+ attr_accessor :on_failed_message
16
+
17
+ # Return the subTransports#send_message result unmodified from #_send_message.
18
+ def _receive_result message, opaque_result
19
+ opaque_result
20
+ end
21
+
22
+ # Return the subTransports#send_message result unmodified from #_send_message.
23
+ def receive_result message, opaque_result
24
+ opaque_result
25
+ end
26
+
27
+ def needs_message_identifier?
28
+ @needs_message_identifier ||
29
+ transports.any? { | t | t.needs_message_identifier? }
30
+ end
31
+
32
+ def needs_message_timestamp?
33
+ @needs_message_timestamp ||
34
+ transports.any? { | t | t.needs_message_timestamp? }
35
+ end
36
+
37
+ # Subclasses with multiple transport should override this method.
38
+ def transports
39
+ @transports ||= [ transport ]
40
+ end
41
+
42
+ # Called from within _send_message rescue.
43
+ def _handle_send_message_exception! transport, message, exc
44
+ _log { [ :send_message, :transport_failed, exc ] }
45
+ (message[:transport_exceptions] ||= [ ]) << "#{exc.inspect}"
46
+ @on_send_message_exception.call(self, message, exc) if @on_send_message_exception
47
+ self
48
+ end
49
+ end
50
+ # !SLIDE END
51
+ end
52
+ end
53
+
@@ -0,0 +1,36 @@
1
+ require 'asir/transport/composite'
2
+
3
+ module ASIR
4
+ class Transport
5
+ # !SLIDE
6
+ # Fallback Transport
7
+ class Fallback < self
8
+ include Composite
9
+
10
+ def _send_message message, message_payload
11
+ result = sent = first_exception = nil
12
+ transports.each do | transport |
13
+ begin
14
+ result = transport.send_message(message)
15
+ sent = true
16
+ break
17
+ rescue ::Exception => exc
18
+ first_exception ||= exc
19
+ _handle_send_message_exception! transport, message, exc
20
+ end
21
+ end
22
+ unless sent
23
+ if first_exception && @reraise_first_exception
24
+ $! = first_exception
25
+ raise
26
+ end
27
+ raise FallbackError, "fallback failed"
28
+ end
29
+ result
30
+ end
31
+ class FallbackError < Error; end
32
+ end
33
+ # !SLIDE END
34
+ end
35
+ end
36
+