asir 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+