cloudpi-appmetric 0.1.0 → 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 (3) hide show
  1. data/VERSION +1 -1
  2. data/lib/cloudpi-appmetric.rb +115 -134
  3. metadata +4 -4
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -1,177 +1,158 @@
1
1
  require 'socket'
2
2
  require 'json'
3
+ require 'thread'
3
4
 
4
5
  module CloudPI
5
6
 
6
7
  class AppMetric
7
-
8
- class CircularQueue
9
-
10
- def initialize(size)
11
- @memory = []
12
- @front = 0
13
- @rear = 0
14
- @lock = Mutex.new
15
-
16
- @queue_size = size
17
- end
18
-
19
- def is_empty
20
- @lock.synchronize { return @front == @rear }
21
- end
22
-
23
- def is_full
24
- @lock.synchronize { return ((@rear + 1) % @queue_size) == @front }
25
- end
26
-
27
- def first
28
- return nil if is_empty
29
- @lock.synchronize { return @memory[(@front + 1) % @queue_size] }
30
- end
31
-
32
- def pop
33
- return if is_empty
34
- @lock.synchronize { @front = (@front + 1) % @queue_size }
35
- end
36
-
37
- def enqueue(data)
38
- if is_full
39
- @lock.synchronize {
40
- @front = (@front + 1) % @queue_size
41
- @rear = (@rear + 1) % @queue_size
42
- @memory[@rear] = data
43
- }
44
- else
45
- @lock.synchronize {
46
- @rear = (@rear + 1) % @queue_size
47
- @memory[@rear] = data
48
- }
49
- end
50
- end
51
-
52
- def dequeue
53
- return nil if is_empty
54
-
55
- @lock.synchronize {
56
- @front = (@front + 1) % @queue_size
57
- return @memory[@front]
58
- }
59
- end
60
-
61
- def cursor
62
- return "#{@front}:#{@rear}"
8
+
9
+ # sleep time in thread loop - checking queue, retrying to connect.
10
+ SLEEP_TIME = 3.0 # sec
11
+
12
+ def initialize(bridge_ip = 'localhost', bridge_port = 5999, policy = '{}')
13
+ @bridge_ip = bridge_ip
14
+ @bridge_port = bridge_port
15
+ @queue = SizedQueue.new(4096)
16
+ @mutex = Mutex.new
17
+
18
+ begin
19
+ json = JSON.parse(ENV['VCAP_APPLICATION'], {:symbolize_names => true})
20
+ @app_ip = json[:host]
21
+ @app_port = json[:port]
22
+ @app_id = json[:app_id]
23
+ @instance_id = json[:instance_id]
24
+ rescue JSON::ParserError, TypeError
25
+ # parsing error: ENV['VCAP_APPLICATION']
26
+ # log error "parsing error: ENV['VCAP_APPLICATION']"
63
27
  end
64
- end
65
-
66
- def initialize(bridge_ip = 'localhost', bridge_port = 5999, metric_policy = '{}')
67
- @app_ip = ENV["VCAP_APP_HOST"] || '127.0.0.1'
68
- @app_port = ENV["VCAP_APP_PORT"] || 9999
69
- env_vcap_application = JSON.parse(ENV["VCAP_APPLICATION"])
70
- app_id = env_vcap_application["app_id"] if env_vcap_application
71
- instance_id = env_vcap_application["instance_id"] if env_vcap_application
72
- @app_id = app_id || ''
73
- @instance_id = instance_id || ''
74
- @bridge_ip = bridge_ip
75
- @bridge_port = bridge_port
76
- @metric_policy = JSON.parse(metric_policy)
77
- @queue = CircularQueue.new(4096)
78
28
 
29
+ @policy = parse(metric_policy)
30
+ @policy_published = false
31
+
32
+ # log info "key: @#!$!"
79
33
  connect
80
- thread_loop
34
+ run
81
35
  end
82
-
36
+
83
37
  def connect
84
38
  begin
85
39
  @conn = TCPSocket.new(@bridge_ip, @bridge_port)
86
- make_policy_unpublished
87
- send_metric_policy
40
+ # log info "connected to bridge"
41
+ @policy_published = false
42
+ send_policy
88
43
  rescue
89
44
  # ignore connection error
45
+ # log error "cann't connect to bridge."
90
46
  nil
91
47
  end
92
48
  end
93
-
49
+
94
50
  def close
95
51
  @conn.close if @conn
52
+ # log info "connection closed"
96
53
  end
97
-
98
- def metric_key
99
- # "IP-ADDRESS:PORT:APP-ID:INSTANCE-ID" or
100
- # "IP-ADDRESS:PORT:APP-INSTANCE-ID".
101
-
102
- # "#{@app_ip}:#{@app_port}:#{@instance_id}"
103
- "#{@app_ip}:#{@app_port}:#{@app_id}:#{@instance_id}"
54
+
55
+ def key
56
+ :"#{@app_ip}:#{@app_port}:#{@app_id}:#{@instance_id}"
104
57
  end
105
-
106
- def set_metric_policy(metric_policy)
107
- # TODO: parse error handling
108
- @metric_policy = JSON.parse(metric_policy)
58
+
59
+ def parse(raw)
60
+ begin
61
+ json = JSON.parse(raw, {:symbolize_names => true})
62
+ json = {} unless json.is_a?(Hash)
63
+ json
64
+ rescue JSON::ParserError
65
+ # log error "parse error"
66
+ {}
67
+ end
109
68
  end
110
-
111
- def make_policy_unpublished
112
- @is_policy_published = false;
69
+
70
+ def circular_enqueue(obj)
71
+ # enqueue like a circular-queue
72
+ # store messages into queue then loop thread will push to bridge
73
+ @mutex.synchronize {
74
+ begin
75
+ while @queue.length >= @queue.max do
76
+ # queue is full.
77
+ # log info "queue is full."
78
+ @queue.pop(true)
79
+ end
80
+ rescue ThreadError
81
+ # queue is empty.
82
+ # log info "queue is empty."
83
+ end
84
+ @queue.push(obj)
85
+ }
113
86
  end
114
-
115
- def send_metric_policy
116
- send_metric_value(@metric_policy.to_json)
117
- @is_policy_published = true;
87
+
88
+ def set_policy(policy)
89
+ @policy = parse(policy)
90
+ # log info "set_policy: #{@policy.to_json}"
118
91
  end
119
-
92
+
93
+ def add_policy(policy)
94
+ # TODO
95
+ end
96
+
97
+ def remove_policy(policy)
98
+ # TODO
99
+ end
100
+
120
101
  def send_heartbeat
121
- send_metric_value({:alive => Time.now.to_i}.to_json)
102
+ # log debug "heartbeat into queue"
103
+ circular_enqueue({:"#{key}" => {:alive => Time.now.to_i}}.to_json)
122
104
  end
123
-
124
- def send_metric_value(message)
125
- # TODO: parse error handling
126
- # add 'when' value into message -> {:when => Time.now, ... }
127
- msg = JSON.parse(message)
105
+
106
+ def send_policy
107
+ # log debug "policy into queue"
108
+ @policy[:when] = Time.now.to_i
109
+ circular_enqueue({:"#{key}" => @policy}.to_json)
110
+ @policy_published = true;
111
+ end
112
+
113
+ def send_metric(metric)
114
+ # log debug "metric into queue"
115
+ msg = parse(metric)
128
116
  msg[:when] = Time.now.to_i
129
- # add metric_key -> {"metric_key":"message"}
130
- message = {metric_key => msg}.to_json
131
-
132
- @queue.enqueue(message)
117
+ circular_enqueue({:"#{key}" => msg}.to_json)
133
118
  end
119
+
120
+ def set_trap(thread)
121
+ # Thread exit when signal triggered
122
+ Signal.trap("TERM") do
123
+ # log info "TERM signal received."
124
+ Thread.kill(thread) if thread
125
+ end
126
+ end
127
+
128
+ def run
129
+ # no needs to send heartbeat, dea will do that..
134
130
 
135
- def thread_loop
136
- thread = Thread.new do
131
+ t = Thread.new do
137
132
  loop do
138
- while !@queue.is_empty do
139
- # puts "not empty queue: #{@queue.cursor}"
140
- @message = @queue.first
133
+
134
+ # log debug "queue capacity: #{@queue.length}/#{@queue.max}"
135
+ while !@queue.empty? do
136
+ @msg = @queue.pop unless @msg # @msg stores last failed msg.
141
137
  begin
142
- @conn.write("#{@message}\0")
143
- # puts "send msg: #{@message}"
144
- @queue.pop
138
+ @conn.write("#{@msg}\0")
139
+ # log debug "send msg: #{@msg}"
140
+ @msg = nil
145
141
  rescue
146
142
  # retry to connect
147
- sleep(1.0)
143
+ # log error "cann't write to bridge."
144
+ sleep(SLEEP_TIME)
148
145
  connect
149
146
  end
150
147
  end # while
151
- sleep(3.0)
152
- end # loop
153
- end # thread
154
-
155
- # no need to send heartbeat, dea metric will do that..
156
-
157
- # heartbeat_thread = Thread.new do
158
- # loop do
159
- # send_heartbeat
160
- # sleep(10.0)
161
- # end # loop
162
- # end # thread
163
-
164
- set_trap(thread)
165
- # set_trap(heartbeat_thread)
166
- end
167
148
 
168
- def set_trap(thread)
169
- # Thread exit when signal triggered
170
- Signal.trap("TERM") do
171
- Thread.kill(thread) if thread
149
+ sleep(SLEEP_TIME) # queue is empty
150
+ end
172
151
  end
152
+
153
+ set_trap(t)
173
154
  end
174
-
155
+
175
156
  end
176
157
 
177
158
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudpi-appmetric
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Junsang Yang
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-10 00:00:00 Z
18
+ date: 2012-06-11 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  type: :development