concord-ruby 0.0.4

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0fd32ec29dc607471dd30ca833037e545be7d3d0
4
+ data.tar.gz: 23db22d170657075bc23e99534d6e4f7daf44b33
5
+ SHA512:
6
+ metadata.gz: ef43347e379410626c26da939574695fef7d5a14afe48e078f0667868d74192fbd3e34398d34219cf68aff8716fc244b36e9e0563acc4ea147ba601e928ab6b6
7
+ data.tar.gz: 73d5ff237e89ee45953f5dc9a0031f3f648e6ef43b0a9a8e21cfb4a0aab8a17d7f79d7e0e4ccf89ba6718caa70c94ad3e4e1f623e54b9287e4a06899a759f87d
data/lib/concord.rb ADDED
@@ -0,0 +1,201 @@
1
+ require 'thrift'
2
+ require 'optparse'
3
+ require 'bolt_proxy_service'
4
+ require 'computation_service'
5
+ require 'bolt_types'
6
+ require 'bolt_constants'
7
+
8
+ module Concord
9
+ # Wrapper over the ComputationMetadata object from the thrift interface
10
+ class Metadata
11
+ attr_accessor :name, :istreams, :ostreams
12
+
13
+ # Initialize a new `Metadata` object
14
+ # @param name [String] The globally unique identifier of the application
15
+ # @param istreams [Array] An array of input streams. These can be formatted
16
+ # as either a `String` identifying the stream or an `Array` of length two,
17
+ # in which the first parameter is the `String` identifier and the second
18
+ # parameter is a `StreamGrouping` defining how incoming records should be
19
+ # routed.
20
+ # @param ostreams [Array] An array of `String` stream identifiers that this
21
+ # computation may produce records on.
22
+ def initialize(name: nil, istreams: [], ostreams: [])
23
+ self.name = name
24
+ self.istreams = istreams
25
+ self.ostreams = ostreams
26
+ end
27
+ end
28
+
29
+ # Transactional wrapper for proxy <=> client interactions
30
+ class ComputationContext
31
+ attr_accessor :transaction, :computation
32
+
33
+ # Initialize a new `ComputationContext`
34
+ # @param computation [Object] The user-defined computation
35
+ def initialize(computation)
36
+ self.computation = computation
37
+ self.transaction = ::Concord::Thrift::ComputationTx.new
38
+ self.transaction.records = []
39
+ self.transaction.timers = {}
40
+ end
41
+
42
+ # Produce a record on `stream` with `key` and `value`
43
+ # @param stream [String] Globally unique name of string
44
+ # @param key [String] Key to group by on stream (pending grouping)
45
+ # @param value [String] Binary blob to pass downstream with tuple
46
+ def produce_record(stream, key, value)
47
+ r = ::Concord::Thrift::Record.new
48
+ r.meta = ::Concord::Thrift::RecordMetadata.new
49
+ r.key = key
50
+ r.data = value
51
+ r.userStream = stream
52
+ transaction.records.push(r)
53
+ end
54
+
55
+ # Set a timer to trigger a callback in the future
56
+ # @param key [String] Name of the timer. This parameter will be passed to
57
+ # the `process_timer` callback to identify the specific callback.
58
+ # @param time [FixNum] Integer representing the time (in milliseconds) at which the callback should be triggered.
59
+ def set_timer(key, time)
60
+ transaction.timers[key] = time
61
+ end
62
+
63
+ # Retrieve a binary blob stored in the proxy state
64
+ # @param key [String] Key to fetch from data store
65
+ # @return [String] Binary blob of data
66
+ def get_state(key)
67
+ computation.get_state(key)
68
+ end
69
+
70
+ # Store a binary blob, identified by a key, in the proxy state
71
+ # @param key [String] Key to set in data store
72
+ # @param value [String] Binary blob
73
+ def set_state(key, value)
74
+ computation.set_state(key, value)
75
+ end
76
+ end
77
+
78
+ # Thrift service definition. Wraps a user-defined computation.
79
+ class Computation
80
+ attr_accessor :handler, :proxy_host, :proxy_port
81
+
82
+ # Initialize a new `Computation` and register it with the proxy
83
+ # @param handler [Object] The user-defined computation
84
+ # @param proxy_host [String] The address the proxy is listening on
85
+ # @param proxy_port [FixNum] The port the proxy is listening on
86
+ def initialize(handler: nil, proxy_host: nil, proxy_port: nil)
87
+ self.handler = handler
88
+ self.proxy_host = proxy_host
89
+ self.proxy_port = proxy_port
90
+ proxy.registerWithScheduler(boltMetadata)
91
+ end
92
+
93
+ # Initialize a new `Computation` and start serving it. This is the only
94
+ # method directly called by users.
95
+ # @param computation [Object] The user-defined computation
96
+ def self.serve(computation)
97
+ listen_address = ENV[::Concord::Thrift::KConcordEnvKeyClientListenAddr]
98
+ proxy_address = ENV[::Concord::Thrift::KConcordEnvKeyClientProxyAddr]
99
+ listen_host, listen_port = listen_address.split(':')
100
+ proxy_host, proxy_port = proxy_address.split(':')
101
+
102
+ handler = self.new(handler: computation,
103
+ proxy_host: proxy_host,
104
+ proxy_port: Integer(proxy_port))
105
+
106
+ processor = Thrift::ComputationService::Processor.new(handler)
107
+ transport = ::Thrift::ServerSocket.new(listen_host, Integer(listen_port))
108
+ transport_factory = ::Thrift::FramedTransportFactory.new
109
+ protocol_factory = ::Thrift::BinaryProtocolAcceleratedFactory.new
110
+ server = ::Thrift::ThreadedServer.new(processor,
111
+ transport,
112
+ transport_factory,
113
+ protocol_factory)
114
+ server.serve
115
+ end
116
+
117
+ # Process an upstream record. Wraps the user method in a transaction, which
118
+ # is returned to the proxy upon completion.
119
+ # @param record [Concord::Thrift::Record] The record to process
120
+ def boltProcessRecord(record)
121
+ ctx = ComputationContext.new(self)
122
+ handler.process_record(ctx, record)
123
+ ctx.transaction
124
+ end
125
+
126
+ # Process a timer callback from the proxy. Wraps the user method in a
127
+ # transaction, which is returned to the proxy upon completion.
128
+ # @param key [String] Callback identifier
129
+ # @param time [FixNum] Time this callback was scheduled to trigger.
130
+ def boltProcessTimer(key, time)
131
+ ctx = ComputationContext.new(self)
132
+ handler.process_timer(ctx, key, time)
133
+ ctx.transaction
134
+ end
135
+
136
+ # The initialization function, called when the framework is ready to start
137
+ # sending the computation records. Wraps the user method in a transaction,
138
+ # which is returned to the proxy upon completion.
139
+ def init
140
+ ctx = ComputationContext.new(self)
141
+ handler.init(ctx)
142
+ ctx.transaction
143
+ end
144
+
145
+ # @return [Concord::Thrift::ComputationMetadata] The user-defined computation metadata.
146
+ def boltMetadata
147
+ metadata = handler.metadata
148
+ enrich_metadata(metadata)
149
+ end
150
+
151
+ # Retrieve a binary blob stored in the proxy state
152
+ # @param key [String] Key to fetch from data store
153
+ # @return [String] Binary blob of data
154
+ def get_state(key)
155
+ proxy.getState(key)
156
+ end
157
+
158
+ # Store a binary blob, identified by a key, in the proxy state
159
+ # @param key [String] Key to set in data store
160
+ # @param value [String] Binary blob
161
+ def set_state(key, value)
162
+ proxy.setState(key, value)
163
+ end
164
+
165
+ private
166
+
167
+ def proxy
168
+ if @proxy.nil? || !@proxy_socket.open?
169
+ @proxy_socket = ::Thrift::Socket.new(proxy_host, proxy_port)
170
+ transport = ::Thrift::FramedTransport.new(@proxy_socket)
171
+ protocol = ::Thrift::BinaryProtocol.new(transport)
172
+ @proxy = ::Concord::Thrift::BoltProxyService::Client.new(protocol)
173
+ transport.open
174
+ end
175
+
176
+ @proxy
177
+ end
178
+
179
+ def enrich_metadata(metadata)
180
+ enrich_stream = ->(stream) {
181
+ name = nil
182
+ grouping = nil
183
+ if stream.is_a?(Array)
184
+ name, grouping = stream
185
+ end
186
+ sm = ::Concord::Thrift::StreamMetadata.new
187
+ sm.name = name
188
+ sm.grouping unless grouping.nil?
189
+ sm
190
+ }
191
+ cm = ::Concord::Thrift::ComputationMetadata.new
192
+ cm.name = metadata.name
193
+ cm.istreams = metadata.istreams.map { |x| enrich_stream.call(x) }
194
+ cm.ostreams = metadata.ostreams.map { |x| enrich_stream.call(x) }
195
+ cm.proxyEndpoint = ::Concord::Thrift::Endpoint.new
196
+ cm.proxyEndpoint.ip = proxy_host
197
+ cm.proxyEndpoint.port = proxy_port
198
+ cm
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,13 @@
1
+ module Concord
2
+ # Some helper functions useful in client computations
3
+ module Utils
4
+ extend self
5
+
6
+ # Get the time in milliseconds
7
+ # @param t [Time] The time to convert to milliseconds
8
+ def time_millis(t = Time.now)
9
+ (t.to_f * 1000.0).to_i
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,47 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.2)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'bolt_types'
9
+
10
+ module Concord
11
+ module Thrift
12
+ KBoltEnvKeyBasePath = %q"BOLT_BASE_PATH"
13
+
14
+ KBoltDefaultEnvBasePath = %q"/tmp/"
15
+
16
+ KBoltEnvKeyPathPrefix = %q"BOLT"
17
+
18
+ KDefaultThriftServiceIOThreads = 2
19
+
20
+ KConcordEnvKeyClientListenAddr = %q"CONCORD_client_listen_address"
21
+
22
+ KConcordEnvKeyClientProxyAddr = %q"CONCORD_client_proxy_address"
23
+
24
+ KDatabasePath = %q"/tmp"
25
+
26
+ KDatabaseEntryTTL = 43200
27
+
28
+ KDefaultBatchSize = 2048
29
+
30
+ KDefaultTraceSampleEveryN = 1024
31
+
32
+ KIncomingMessageQueueTopic = %q"incoming"
33
+
34
+ KOutgoingMessageQueueTopic = %q"outgoing"
35
+
36
+ KQueueStreamNameToIdMapTopic = %q"stream_map"
37
+
38
+ KMessageQueueWatermarkTopic = %q"watermarks"
39
+
40
+ KMessageQueueBatchSize = 1024
41
+
42
+ KMessageQueueTTL = 21600
43
+
44
+ KBoltTraceHeader = %q"bolt_traces"
45
+
46
+ end
47
+ end
@@ -0,0 +1,151 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.2)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'bolt_types'
9
+
10
+ module Concord
11
+ module Thrift
12
+ module BoltManagerService
13
+ class Client
14
+ include ::Thrift::Client
15
+
16
+ def setEnvironmentVar(name, value)
17
+ send_setEnvironmentVar(name, value)
18
+ recv_setEnvironmentVar()
19
+ end
20
+
21
+ def send_setEnvironmentVar(name, value)
22
+ send_message('setEnvironmentVar', SetEnvironmentVar_args, :name => name, :value => value)
23
+ end
24
+
25
+ def recv_setEnvironmentVar()
26
+ result = receive_message(SetEnvironmentVar_result)
27
+ raise result.e unless result.e.nil?
28
+ return
29
+ end
30
+
31
+ def signal(topologyId, s)
32
+ send_signal(topologyId, s)
33
+ recv_signal()
34
+ end
35
+
36
+ def send_signal(topologyId, s)
37
+ send_message('signal', Signal_args, :topologyId => topologyId, :s => s)
38
+ end
39
+
40
+ def recv_signal()
41
+ result = receive_message(Signal_result)
42
+ raise result.e unless result.e.nil?
43
+ return
44
+ end
45
+
46
+ end
47
+
48
+ class Processor
49
+ include ::Thrift::Processor
50
+
51
+ def process_setEnvironmentVar(seqid, iprot, oprot)
52
+ args = read_args(iprot, SetEnvironmentVar_args)
53
+ result = SetEnvironmentVar_result.new()
54
+ begin
55
+ @handler.setEnvironmentVar(args.name, args.value)
56
+ rescue ::Concord::Thrift::BoltError => e
57
+ result.e = e
58
+ end
59
+ write_result(result, oprot, 'setEnvironmentVar', seqid)
60
+ end
61
+
62
+ def process_signal(seqid, iprot, oprot)
63
+ args = read_args(iprot, Signal_args)
64
+ result = Signal_result.new()
65
+ begin
66
+ @handler.signal(args.topologyId, args.s)
67
+ rescue ::Concord::Thrift::BoltError => e
68
+ result.e = e
69
+ end
70
+ write_result(result, oprot, 'signal', seqid)
71
+ end
72
+
73
+ end
74
+
75
+ # HELPER FUNCTIONS AND STRUCTURES
76
+
77
+ class SetEnvironmentVar_args
78
+ include ::Thrift::Struct, ::Thrift::Struct_Union
79
+ NAME = 1
80
+ VALUE = 2
81
+
82
+ FIELDS = {
83
+ NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
84
+ VALUE => {:type => ::Thrift::Types::STRING, :name => 'value'}
85
+ }
86
+
87
+ def struct_fields; FIELDS; end
88
+
89
+ def validate
90
+ end
91
+
92
+ ::Thrift::Struct.generate_accessors self
93
+ end
94
+
95
+ class SetEnvironmentVar_result
96
+ include ::Thrift::Struct, ::Thrift::Struct_Union
97
+ E = 1
98
+
99
+ FIELDS = {
100
+ E => {:type => ::Thrift::Types::STRUCT, :name => 'e', :class => ::Concord::Thrift::BoltError}
101
+ }
102
+
103
+ def struct_fields; FIELDS; end
104
+
105
+ def validate
106
+ end
107
+
108
+ ::Thrift::Struct.generate_accessors self
109
+ end
110
+
111
+ class Signal_args
112
+ include ::Thrift::Struct, ::Thrift::Struct_Union
113
+ TOPOLOGYID = 1
114
+ S = 2
115
+
116
+ FIELDS = {
117
+ TOPOLOGYID => {:type => ::Thrift::Types::I64, :name => 'topologyId'},
118
+ S => {:type => ::Thrift::Types::I32, :name => 's', :enum_class => ::Concord::Thrift::Signal}
119
+ }
120
+
121
+ def struct_fields; FIELDS; end
122
+
123
+ def validate
124
+ unless @s.nil? || ::Concord::Thrift::Signal::VALID_VALUES.include?(@s)
125
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field s!')
126
+ end
127
+ end
128
+
129
+ ::Thrift::Struct.generate_accessors self
130
+ end
131
+
132
+ class Signal_result
133
+ include ::Thrift::Struct, ::Thrift::Struct_Union
134
+ E = 1
135
+
136
+ FIELDS = {
137
+ E => {:type => ::Thrift::Types::STRUCT, :name => 'e', :class => ::Concord::Thrift::BoltError}
138
+ }
139
+
140
+ def struct_fields; FIELDS; end
141
+
142
+ def validate
143
+ end
144
+
145
+ ::Thrift::Struct.generate_accessors self
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,268 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.2)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'bolt_types'
9
+
10
+ module Concord
11
+ module Thrift
12
+ module BoltMetricsService
13
+ class Client
14
+ include ::Thrift::Client
15
+
16
+ def gauge(name, val)
17
+ send_gauge(name, val)
18
+ recv_gauge()
19
+ end
20
+
21
+ def send_gauge(name, val)
22
+ send_message('gauge', Gauge_args, :name => name, :val => val)
23
+ end
24
+
25
+ def recv_gauge()
26
+ result = receive_message(Gauge_result)
27
+ raise result.e unless result.e.nil?
28
+ return
29
+ end
30
+
31
+ def timer(name, duration)
32
+ send_timer(name, duration)
33
+ recv_timer()
34
+ end
35
+
36
+ def send_timer(name, duration)
37
+ send_message('timer', Timer_args, :name => name, :duration => duration)
38
+ end
39
+
40
+ def recv_timer()
41
+ result = receive_message(Timer_result)
42
+ raise result.e unless result.e.nil?
43
+ return
44
+ end
45
+
46
+ def histogram(name, measure)
47
+ send_histogram(name, measure)
48
+ recv_histogram()
49
+ end
50
+
51
+ def send_histogram(name, measure)
52
+ send_message('histogram', Histogram_args, :name => name, :measure => measure)
53
+ end
54
+
55
+ def recv_histogram()
56
+ result = receive_message(Histogram_result)
57
+ raise result.e unless result.e.nil?
58
+ return
59
+ end
60
+
61
+ def sum(name, counter)
62
+ send_sum(name, counter)
63
+ recv_sum()
64
+ end
65
+
66
+ def send_sum(name, counter)
67
+ send_message('sum', Sum_args, :name => name, :counter => counter)
68
+ end
69
+
70
+ def recv_sum()
71
+ result = receive_message(Sum_result)
72
+ raise result.e unless result.e.nil?
73
+ return
74
+ end
75
+
76
+ end
77
+
78
+ class Processor
79
+ include ::Thrift::Processor
80
+
81
+ def process_gauge(seqid, iprot, oprot)
82
+ args = read_args(iprot, Gauge_args)
83
+ result = Gauge_result.new()
84
+ begin
85
+ @handler.gauge(args.name, args.val)
86
+ rescue ::Concord::Thrift::BoltError => e
87
+ result.e = e
88
+ end
89
+ write_result(result, oprot, 'gauge', seqid)
90
+ end
91
+
92
+ def process_timer(seqid, iprot, oprot)
93
+ args = read_args(iprot, Timer_args)
94
+ result = Timer_result.new()
95
+ begin
96
+ @handler.timer(args.name, args.duration)
97
+ rescue ::Concord::Thrift::BoltError => e
98
+ result.e = e
99
+ end
100
+ write_result(result, oprot, 'timer', seqid)
101
+ end
102
+
103
+ def process_histogram(seqid, iprot, oprot)
104
+ args = read_args(iprot, Histogram_args)
105
+ result = Histogram_result.new()
106
+ begin
107
+ @handler.histogram(args.name, args.measure)
108
+ rescue ::Concord::Thrift::BoltError => e
109
+ result.e = e
110
+ end
111
+ write_result(result, oprot, 'histogram', seqid)
112
+ end
113
+
114
+ def process_sum(seqid, iprot, oprot)
115
+ args = read_args(iprot, Sum_args)
116
+ result = Sum_result.new()
117
+ begin
118
+ @handler.sum(args.name, args.counter)
119
+ rescue ::Concord::Thrift::BoltError => e
120
+ result.e = e
121
+ end
122
+ write_result(result, oprot, 'sum', seqid)
123
+ end
124
+
125
+ end
126
+
127
+ # HELPER FUNCTIONS AND STRUCTURES
128
+
129
+ class Gauge_args
130
+ include ::Thrift::Struct, ::Thrift::Struct_Union
131
+ NAME = 1
132
+ VAL = 2
133
+
134
+ FIELDS = {
135
+ NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
136
+ VAL => {:type => ::Thrift::Types::I64, :name => 'val'}
137
+ }
138
+
139
+ def struct_fields; FIELDS; end
140
+
141
+ def validate
142
+ end
143
+
144
+ ::Thrift::Struct.generate_accessors self
145
+ end
146
+
147
+ class Gauge_result
148
+ include ::Thrift::Struct, ::Thrift::Struct_Union
149
+ E = 1
150
+
151
+ FIELDS = {
152
+ E => {:type => ::Thrift::Types::STRUCT, :name => 'e', :class => ::Concord::Thrift::BoltError}
153
+ }
154
+
155
+ def struct_fields; FIELDS; end
156
+
157
+ def validate
158
+ end
159
+
160
+ ::Thrift::Struct.generate_accessors self
161
+ end
162
+
163
+ class Timer_args
164
+ include ::Thrift::Struct, ::Thrift::Struct_Union
165
+ NAME = 1
166
+ DURATION = 2
167
+
168
+ FIELDS = {
169
+ NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
170
+ DURATION => {:type => ::Thrift::Types::I64, :name => 'duration'}
171
+ }
172
+
173
+ def struct_fields; FIELDS; end
174
+
175
+ def validate
176
+ end
177
+
178
+ ::Thrift::Struct.generate_accessors self
179
+ end
180
+
181
+ class Timer_result
182
+ include ::Thrift::Struct, ::Thrift::Struct_Union
183
+ E = 1
184
+
185
+ FIELDS = {
186
+ E => {:type => ::Thrift::Types::STRUCT, :name => 'e', :class => ::Concord::Thrift::BoltError}
187
+ }
188
+
189
+ def struct_fields; FIELDS; end
190
+
191
+ def validate
192
+ end
193
+
194
+ ::Thrift::Struct.generate_accessors self
195
+ end
196
+
197
+ class Histogram_args
198
+ include ::Thrift::Struct, ::Thrift::Struct_Union
199
+ NAME = 1
200
+ MEASURE = 2
201
+
202
+ FIELDS = {
203
+ NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
204
+ MEASURE => {:type => ::Thrift::Types::I64, :name => 'measure'}
205
+ }
206
+
207
+ def struct_fields; FIELDS; end
208
+
209
+ def validate
210
+ end
211
+
212
+ ::Thrift::Struct.generate_accessors self
213
+ end
214
+
215
+ class Histogram_result
216
+ include ::Thrift::Struct, ::Thrift::Struct_Union
217
+ E = 1
218
+
219
+ FIELDS = {
220
+ E => {:type => ::Thrift::Types::STRUCT, :name => 'e', :class => ::Concord::Thrift::BoltError}
221
+ }
222
+
223
+ def struct_fields; FIELDS; end
224
+
225
+ def validate
226
+ end
227
+
228
+ ::Thrift::Struct.generate_accessors self
229
+ end
230
+
231
+ class Sum_args
232
+ include ::Thrift::Struct, ::Thrift::Struct_Union
233
+ NAME = 1
234
+ COUNTER = 2
235
+
236
+ FIELDS = {
237
+ NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
238
+ COUNTER => {:type => ::Thrift::Types::I64, :name => 'counter'}
239
+ }
240
+
241
+ def struct_fields; FIELDS; end
242
+
243
+ def validate
244
+ end
245
+
246
+ ::Thrift::Struct.generate_accessors self
247
+ end
248
+
249
+ class Sum_result
250
+ include ::Thrift::Struct, ::Thrift::Struct_Union
251
+ E = 1
252
+
253
+ FIELDS = {
254
+ E => {:type => ::Thrift::Types::STRUCT, :name => 'e', :class => ::Concord::Thrift::BoltError}
255
+ }
256
+
257
+ def struct_fields; FIELDS; end
258
+
259
+ def validate
260
+ end
261
+
262
+ ::Thrift::Struct.generate_accessors self
263
+ end
264
+
265
+ end
266
+
267
+ end
268
+ end