cosmos 5.0.3 → 5.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 +4 -4
- data/bin/cosmos +1 -1
- data/lib/cosmos/api/api.rb +1 -25
- data/lib/cosmos/api/cmd_api.rb +6 -6
- data/lib/cosmos/api/config_api.rb +10 -4
- data/lib/cosmos/api/limits_api.rb +1 -1
- data/lib/cosmos/api/settings_api.rb +19 -7
- data/lib/cosmos/api/target_api.rb +2 -2
- data/lib/cosmos/api/tlm_api.rb +8 -8
- data/lib/cosmos/config/config_parser.rb +2 -2
- data/lib/cosmos/config/meta_config_parser.rb +1 -1
- data/lib/cosmos/logs/log_writer.rb +2 -2
- data/lib/cosmos/microservices/decom_microservice.rb +1 -1
- data/lib/cosmos/microservices/interface_microservice.rb +0 -1
- data/lib/cosmos/microservices/microservice.rb +2 -2
- data/lib/cosmos/microservices/reducer_microservice.rb +12 -10
- data/lib/cosmos/models/cvt_model.rb +6 -6
- data/lib/cosmos/models/gem_model.rb +2 -2
- data/lib/cosmos/models/info_model.rb +1 -1
- data/lib/cosmos/models/interface_status_model.rb +1 -1
- data/lib/cosmos/models/metadata_model.rb +42 -216
- data/lib/cosmos/models/metric_model.rb +2 -2
- data/lib/cosmos/models/microservice_model.rb +1 -1
- data/lib/cosmos/models/microservice_status_model.rb +1 -1
- data/lib/cosmos/models/model.rb +16 -16
- data/lib/cosmos/models/note_model.rb +124 -0
- data/lib/cosmos/models/ping_model.rb +2 -1
- data/lib/cosmos/models/plugin_model.rb +1 -1
- data/lib/cosmos/models/process_status_model.rb +1 -1
- data/lib/cosmos/models/scope_model.rb +9 -6
- data/lib/cosmos/models/settings_model.rb +55 -0
- data/lib/cosmos/models/sorted_model.rb +165 -0
- data/lib/cosmos/models/target_model.rb +20 -20
- data/lib/cosmos/models/tool_config_model.rb +38 -0
- data/lib/cosmos/models/tool_model.rb +1 -1
- data/lib/cosmos/models/widget_model.rb +1 -1
- data/lib/cosmos/operators/microservice_operator.rb +2 -1
- data/lib/cosmos/script/calendar.rb +26 -15
- data/lib/cosmos/system/system.rb +2 -1
- data/lib/cosmos/top_level.rb +5 -1
- data/lib/cosmos/topics/autonomic_topic.rb +2 -2
- data/lib/cosmos/topics/calendar_topic.rb +1 -1
- data/lib/cosmos/topics/command_decom_topic.rb +31 -1
- data/lib/cosmos/topics/command_topic.rb +6 -4
- data/lib/cosmos/topics/interface_topic.rb +8 -8
- data/lib/cosmos/topics/limits_event_topic.rb +5 -3
- data/lib/cosmos/topics/notifications_topic.rb +1 -1
- data/lib/cosmos/topics/router_topic.rb +9 -9
- data/lib/cosmos/topics/telemetry_decom_topic.rb +1 -1
- data/lib/cosmos/topics/telemetry_topic.rb +1 -1
- data/lib/cosmos/topics/timeline_topic.rb +1 -1
- data/lib/cosmos/topics/topic.rb +21 -16
- data/lib/cosmos/utilities/logger.rb +3 -3
- data/lib/cosmos/utilities/metric.rb +32 -26
- data/lib/cosmos/utilities/s3.rb +1 -1
- data/lib/cosmos/utilities/s3_file_cache.rb +12 -6
- data/lib/cosmos/utilities/store.rb +1 -0
- data/lib/cosmos/utilities/store_autoload.rb +27 -126
- data/lib/cosmos/version.rb +5 -5
- metadata +7 -4
- data/lib/cosmos/models/narrative_model.rb +0 -280
@@ -34,38 +34,38 @@ module Cosmos
|
|
34
34
|
|
35
35
|
def self.receive_commands(interface, scope:)
|
36
36
|
while true
|
37
|
-
|
37
|
+
Topic.read_topics(InterfaceTopic.topics(interface, scope: scope)) do |topic, msg_id, msg_hash, redis|
|
38
38
|
result = yield topic, msg_hash
|
39
39
|
ack_topic = topic.split("__")
|
40
40
|
ack_topic[1] = 'ACK' + ack_topic[1]
|
41
41
|
ack_topic = ack_topic.join("__")
|
42
|
-
|
42
|
+
Topic.write_topic(ack_topic, { 'result' => result, 'id' => msg_id }, '*', 100)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.write_raw(interface_name, data, scope:)
|
48
|
-
|
48
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'raw' => data }, '*', 100)
|
49
49
|
end
|
50
50
|
|
51
51
|
def self.connect_interface(interface_name, scope:)
|
52
|
-
|
52
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'connect' => 'true' }, '*', 100)
|
53
53
|
end
|
54
54
|
|
55
55
|
def self.disconnect_interface(interface_name, scope:)
|
56
|
-
|
56
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'disconnect' => 'true' }, '*', 100)
|
57
57
|
end
|
58
58
|
|
59
59
|
def self.start_raw_logging(interface_name, scope:)
|
60
|
-
|
60
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'log_raw' => 'true' }, '*', 100)
|
61
61
|
end
|
62
62
|
|
63
63
|
def self.stop_raw_logging(interface_name, scope:)
|
64
|
-
|
64
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'log_raw' => 'false' }, '*', 100)
|
65
65
|
end
|
66
66
|
|
67
67
|
def self.shutdown(interface, scope:)
|
68
|
-
|
68
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface.name}", { 'shutdown' => 'true' }, '*', 100)
|
69
69
|
sleep 1 # Give some time for the interface to shutdown
|
70
70
|
InterfaceTopic.clear_topics(InterfaceTopic.topics(interface, scope: scope))
|
71
71
|
end
|
@@ -52,13 +52,13 @@ module Cosmos
|
|
52
52
|
raise "Invalid limits event type '#{event[:type]}'"
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
Topic.write_topic("#{scope}__cosmos_limits_events", event, '*', 1000)
|
56
56
|
end
|
57
57
|
|
58
58
|
def self.read(offset = nil, count: 100, scope:)
|
59
59
|
topic = "#{scope}__cosmos_limits_events"
|
60
60
|
if offset
|
61
|
-
result =
|
61
|
+
result = Topic.read_topics([topic], [offset], nil, count)
|
62
62
|
if result.empty?
|
63
63
|
[] # We want to return an empty array rather than an empty hash
|
64
64
|
else
|
@@ -67,7 +67,9 @@ module Cosmos
|
|
67
67
|
result[topic]
|
68
68
|
end
|
69
69
|
else
|
70
|
-
|
70
|
+
result = Topic.get_newest_message(topic)
|
71
|
+
return [result] if result
|
72
|
+
return []
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
@@ -22,7 +22,7 @@ require 'cosmos/topics/topic'
|
|
22
22
|
module Cosmos
|
23
23
|
class NotificationsTopic < Topic
|
24
24
|
def self.write_notification(notification, scope:)
|
25
|
-
|
25
|
+
Topic.write_topic("#{scope}__cosmos_notifications", notification)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -36,13 +36,13 @@ module Cosmos
|
|
36
36
|
|
37
37
|
def self.receive_telemetry(router, scope:)
|
38
38
|
while true
|
39
|
-
|
39
|
+
Topic.read_topics(RouterTopic.topics(router, scope: scope)) do |topic, msg_id, msg_hash, redis|
|
40
40
|
result = yield topic, msg_hash
|
41
41
|
if /CMD}ROUTER/.match?(topic)
|
42
42
|
ack_topic = topic.split("__")
|
43
43
|
ack_topic[1] = 'ACK' + ack_topic[1]
|
44
44
|
ack_topic = ack_topic.join("__")
|
45
|
-
|
45
|
+
Topic.write_topic(ack_topic, { 'result' => result }, msg_id, 100)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -51,33 +51,33 @@ module Cosmos
|
|
51
51
|
def self.route_command(packet, target_names, scope:)
|
52
52
|
if packet.identified?
|
53
53
|
topic = "{#{scope}__CMD}TARGET__#{packet.target_name}"
|
54
|
-
|
54
|
+
Topic.write_topic(topic, { 'target_name' => packet.target_name, 'cmd_name' => packet.packet_name, 'cmd_buffer' => packet.buffer(false) }, '*', 100)
|
55
55
|
elsif target_names.length == 1
|
56
56
|
topic = "{#{scope}__CMD}TARGET__#{target_names[0]}"
|
57
|
-
|
57
|
+
Topic.write_topic(topic, { 'target_name' => packet.target_name, 'cmd_name' => 'UNKNOWN', 'cmd_buffer' => packet.buffer(false) }, '*', 100)
|
58
58
|
else
|
59
59
|
raise "No route for command: #{packet.target_name} #{packet.packet_name}"
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
def self.connect_router(router_name, scope:)
|
64
|
-
|
64
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'connect' => true }, '*', 100)
|
65
65
|
end
|
66
66
|
|
67
67
|
def self.disconnect_router(router_name, scope:)
|
68
|
-
|
68
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'disconnect' => true }, '*', 100)
|
69
69
|
end
|
70
70
|
|
71
71
|
def self.start_raw_logging(router_name, scope:)
|
72
|
-
|
72
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'log_raw' => 'true' }, '*', 100)
|
73
73
|
end
|
74
74
|
|
75
75
|
def self.stop_raw_logging(router_name, scope:)
|
76
|
-
|
76
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'log_raw' => 'false' }, '*', 100)
|
77
77
|
end
|
78
78
|
|
79
79
|
def self.shutdown(router, scope:)
|
80
|
-
|
80
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router.name}", { 'shutdown' => 'true' }, '*', 100)
|
81
81
|
sleep 1 # Give some time for the interface to shutdown
|
82
82
|
RouterTopic.clear_topics(RouterTopic.topics(router, scope: scope))
|
83
83
|
end
|
@@ -43,7 +43,7 @@ module Cosmos
|
|
43
43
|
:received_count => packet.received_count,
|
44
44
|
:json_data => JSON.generate(json_hash.as_json),
|
45
45
|
}
|
46
|
-
|
46
|
+
Topic.write_topic("#{scope}__DECOM__{#{packet.target_name}}__#{packet.packet_name}", msg_hash, id)
|
47
47
|
# Also update the current value table with the latest decommutated data
|
48
48
|
CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, scope: scope)
|
49
49
|
end
|
@@ -30,7 +30,7 @@ module Cosmos
|
|
30
30
|
:received_count => packet.received_count,
|
31
31
|
:buffer => packet.buffer(false),
|
32
32
|
}
|
33
|
-
|
33
|
+
Topic.write_topic("#{scope}__TELEMETRY__{#{packet.target_name}}__#{packet.packet_name}", msg_hash)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
data/lib/cosmos/topics/topic.rb
CHANGED
@@ -21,28 +21,33 @@ require 'cosmos/utilities/store'
|
|
21
21
|
|
22
22
|
module Cosmos
|
23
23
|
class Topic
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
if RUBY_VERSION < "3"
|
25
|
+
# Delegate all unknown class methods to delegate to the EphemeralStore
|
26
|
+
def self.method_missing(message, *args, &block)
|
27
|
+
EphemeralStore.public_send(message, *args, &block)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
# Delegate all unknown class methods to delegate to the EphemeralStore
|
31
|
+
def self.method_missing(message, *args, **kwargs, &block)
|
32
|
+
EphemeralStore.public_send(message, *args, **kwargs, &block)
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
def self.clear_topics(topics, maxlen = 0)
|
33
|
-
topics.each
|
34
|
-
Store.xtrim(topic, maxlen)
|
35
|
-
end
|
37
|
+
topics.each { |topic| EphemeralStore.xtrim(topic, maxlen) }
|
36
38
|
end
|
37
39
|
|
38
40
|
def self.topics(scope, key)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
EphemeralStore
|
42
|
+
.scan_each(match: "#{scope}__#{key}__*", type: 'stream', count: 100)
|
43
|
+
.to_a # Change the enumerator into an array
|
44
|
+
.uniq # Scan can return duplicates so ensure unique
|
45
|
+
.sort # Sort not entirely necessary but nice
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.get_cnt(topic)
|
49
|
+
_, packet = EphemeralStore.get_newest_message(topic)
|
50
|
+
packet ? packet["received_count"].to_i : 0
|
46
51
|
end
|
47
52
|
end
|
48
53
|
end
|
@@ -19,7 +19,7 @@
|
|
19
19
|
|
20
20
|
require 'cosmos/core_ext/class'
|
21
21
|
require 'cosmos/core_ext/time'
|
22
|
-
require 'cosmos/
|
22
|
+
require 'cosmos/topics/topic'
|
23
23
|
require 'socket'
|
24
24
|
require 'logger'
|
25
25
|
require 'time'
|
@@ -174,11 +174,11 @@ module Cosmos
|
|
174
174
|
puts data.to_json if @stdout
|
175
175
|
unless @no_store
|
176
176
|
if scope
|
177
|
-
|
177
|
+
Topic.write_topic("#{scope}__cosmos_log_messages", data)
|
178
178
|
else
|
179
179
|
# The base cosmos_log_messages doesn't have an associated logger
|
180
180
|
# so it must be limited to prevent unbounded stream growth
|
181
|
-
|
181
|
+
Topic.write_topic("cosmos_log_messages", data, '*', 1000)
|
182
182
|
end
|
183
183
|
end
|
184
184
|
end
|
@@ -18,6 +18,7 @@
|
|
18
18
|
# copyright holder
|
19
19
|
|
20
20
|
require 'cosmos/models/metric_model'
|
21
|
+
require 'thread'
|
21
22
|
|
22
23
|
module Cosmos
|
23
24
|
class Metric
|
@@ -48,6 +49,7 @@ module Cosmos
|
|
48
49
|
@scope = scope
|
49
50
|
@microservice = microservice
|
50
51
|
@size = 5000
|
52
|
+
@mutex = Mutex.new
|
51
53
|
end
|
52
54
|
|
53
55
|
def add_sample(name:, value:, labels:)
|
@@ -69,15 +71,17 @@ module Cosmos
|
|
69
71
|
# the value is added to @items and the count of the value is increased
|
70
72
|
# if the count of the values exceed the size of the array it sets the
|
71
73
|
# count back to zero and the array will over write older data.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
74
|
+
@mutex.synchronize do
|
75
|
+
key = "#{name}|" + labels.map { |k, v| "#{k}=#{v}" }.join(',')
|
76
|
+
if not @items.has_key?(key)
|
77
|
+
Logger.debug("new data for #{@scope}, #{key}")
|
78
|
+
@items[key] = { 'values' => Array.new(@size), 'count' => 0 }
|
79
|
+
end
|
80
|
+
count = @items[key]['count']
|
81
|
+
# Logger.info("adding data for #{@scope}, #{count} #{key}, #{value}")
|
82
|
+
@items[key]['values'][count] = value
|
83
|
+
@items[key]['count'] = count + 1 >= @size ? 0 : count + 1
|
76
84
|
end
|
77
|
-
count = @items[key]['count']
|
78
|
-
# Logger.info("adding data for #{@scope}, #{count} #{key}, #{value}")
|
79
|
-
@items[key]['values'][count] = value
|
80
|
-
@items[key]['count'] = count + 1 >= @size ? 0 : count + 1
|
81
85
|
end
|
82
86
|
|
83
87
|
def percentile(sorted_values, percentile)
|
@@ -106,24 +110,26 @@ module Cosmos
|
|
106
110
|
# array. to store the array as the value with the metric name again joined
|
107
111
|
# with the @microservice and @scope.
|
108
112
|
Logger.debug("#{@microservice} #{@scope} sending metrics to redis, #{@items.length}") if @items.length > 0
|
109
|
-
@
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
113
|
+
@mutex.synchronize do
|
114
|
+
@items.each do |key, values|
|
115
|
+
label_list = []
|
116
|
+
name, labels = key.split('|')
|
117
|
+
metric_labels = labels.nil? ? {} : labels.split(',').map { |x| x.split('=') }.map { |k, v| { k => v } }.reduce({}, :merge)
|
118
|
+
sorted_values = values['values'].compact.sort
|
119
|
+
for percentile_value in [10, 50, 90, 95, 99]
|
120
|
+
percentile_result = percentile(sorted_values, percentile_value)
|
121
|
+
labels = metric_labels.clone.merge({ 'scope' => @scope, 'microservice' => @microservice })
|
122
|
+
labels['percentile'] = percentile_value
|
123
|
+
labels['metric__value'] = percentile_result
|
124
|
+
label_list.append(labels)
|
125
|
+
end
|
126
|
+
begin
|
127
|
+
Logger.debug("sending metrics summary to redis key: #{@microservice}")
|
128
|
+
metric = MetricModel.new(name: @microservice, scope: @scope, metric_name: name, label_list: label_list)
|
129
|
+
metric.create(force: true)
|
130
|
+
rescue RuntimeError
|
131
|
+
Logger.error("failed attempt to update metric, #{key}, #{name} #{@scope}")
|
132
|
+
end
|
127
133
|
end
|
128
134
|
end
|
129
135
|
end
|
data/lib/cosmos/utilities/s3.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
# copyright holder
|
19
19
|
|
20
20
|
require 'fileutils'
|
21
|
+
require 'tmpdir'
|
21
22
|
require 'cosmos'
|
22
23
|
require 'cosmos/utilities/s3'
|
23
24
|
|
@@ -48,7 +49,7 @@ class S3File
|
|
48
49
|
|
49
50
|
def retrieve
|
50
51
|
local_path = "#{S3FileCache.instance.cache_dir}/#{File.basename(@s3_path)}"
|
51
|
-
Cosmos::Logger.
|
52
|
+
Cosmos::Logger.debug "Retrieving #{@s3_path} from logs bucket"
|
52
53
|
@rubys3_client.get_object(bucket: "logs", key: @s3_path, response_target: local_path)
|
53
54
|
if File.exist?(local_path)
|
54
55
|
@size = File.size(local_path)
|
@@ -57,6 +58,7 @@ class S3File
|
|
57
58
|
rescue => err
|
58
59
|
@error = err
|
59
60
|
Cosmos::Logger.error "Failed to retrieve #{@s3_path}\n#{err.formatted}"
|
61
|
+
raise err
|
60
62
|
end
|
61
63
|
|
62
64
|
def reserve
|
@@ -165,11 +167,11 @@ class S3FileCache
|
|
165
167
|
end
|
166
168
|
|
167
169
|
# Create local file cache location
|
168
|
-
@cache_dir =
|
170
|
+
@cache_dir = Dir.mktmpdir
|
169
171
|
FileUtils.mkdir_p(@cache_dir)
|
170
|
-
|
171
|
-
|
172
|
-
|
172
|
+
at_exit do
|
173
|
+
FileUtils.remove_dir(@cache_dir, true)
|
174
|
+
end
|
173
175
|
|
174
176
|
@cached_files = S3FileCollection.new
|
175
177
|
|
@@ -178,7 +180,11 @@ class S3FileCache
|
|
178
180
|
file = @cached_files.get_next_to_retrieve
|
179
181
|
# Cosmos::Logger.debug "Next file: #{file}"
|
180
182
|
if file and (file.size + @cached_files.current_disk_usage()) <= @max_disk_usage
|
181
|
-
|
183
|
+
begin
|
184
|
+
file.retrieve
|
185
|
+
rescue
|
186
|
+
# Will be automatically retried
|
187
|
+
end
|
182
188
|
else
|
183
189
|
sleep(1)
|
184
190
|
end
|
@@ -31,7 +31,7 @@ end
|
|
31
31
|
module Cosmos
|
32
32
|
class Store
|
33
33
|
# Variable that holds the singleton instance
|
34
|
-
|
34
|
+
@instance = nil
|
35
35
|
|
36
36
|
# Mutex used to ensure that only one instance is created
|
37
37
|
@@instance_mutex = Mutex.new
|
@@ -42,11 +42,11 @@ module Cosmos
|
|
42
42
|
# Get the singleton instance
|
43
43
|
def self.instance(pool_size = 100)
|
44
44
|
# Logger.level = Logger::DEBUG
|
45
|
-
return
|
45
|
+
return @instance if @instance
|
46
46
|
|
47
47
|
@@instance_mutex.synchronize do
|
48
|
-
|
49
|
-
return
|
48
|
+
@instance ||= self.new(pool_size)
|
49
|
+
return @instance
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -87,44 +87,10 @@ module Cosmos
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
def get_cmd_item(target_name, packet_name, param_name, type: :WITH_UNITS, scope: $cosmos_scope)
|
91
|
-
msg_id, msg_hash = read_topic_last("#{scope}__DECOMCMD__{#{target_name}}__#{packet_name}")
|
92
|
-
if msg_id
|
93
|
-
# TODO: We now have these reserved items directly on command packets
|
94
|
-
# Do we still calculate from msg_hash['time'] or use the times directly?
|
95
|
-
#
|
96
|
-
# if param_name == 'RECEIVED_TIMESECONDS' || param_name == 'PACKET_TIMESECONDS'
|
97
|
-
# Time.from_nsec_from_epoch(msg_hash['time'].to_i).to_f
|
98
|
-
# elsif param_name == 'RECEIVED_TIMEFORMATTED' || param_name == 'PACKET_TIMEFORMATTED'
|
99
|
-
# Time.from_nsec_from_epoch(msg_hash['time'].to_i).formatted
|
100
|
-
if param_name == 'RECEIVED_COUNT'
|
101
|
-
msg_hash['received_count'].to_i
|
102
|
-
else
|
103
|
-
json = msg_hash['json_data']
|
104
|
-
hash = JSON.parse(json)
|
105
|
-
# Start from the most complex down to the basic raw value
|
106
|
-
value = hash["#{param_name}__U"]
|
107
|
-
return value if value && type == :WITH_UNITS
|
108
|
-
|
109
|
-
value = hash["#{param_name}__F"]
|
110
|
-
return value if value && (type == :WITH_UNITS || type == :FORMATTED)
|
111
|
-
|
112
|
-
value = hash["#{param_name}__C"]
|
113
|
-
return value if value && (type == :WITH_UNITS || type == :FORMATTED || type == :CONVERTED)
|
114
|
-
|
115
|
-
return hash[param_name]
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
90
|
###########################################################################
|
121
91
|
# Stream APIs
|
122
92
|
###########################################################################
|
123
93
|
|
124
|
-
def self.initialize_streams(topics)
|
125
|
-
self.instance.initialize_streams(topics)
|
126
|
-
end
|
127
|
-
|
128
94
|
def initialize_streams(topics)
|
129
95
|
@redis_pool.with do |redis|
|
130
96
|
topics.each do |topic|
|
@@ -134,48 +100,18 @@ module Cosmos
|
|
134
100
|
end
|
135
101
|
end
|
136
102
|
|
137
|
-
def self.get_oldest_message(topic)
|
138
|
-
self.instance.get_oldest_message(topic)
|
139
|
-
end
|
140
|
-
|
141
103
|
def get_oldest_message(topic)
|
142
104
|
@redis_pool.with do |redis|
|
143
105
|
result = redis.xrange(topic, count: 1)
|
144
|
-
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
def self.get_newest_message(topic)
|
149
|
-
self.instance.get_newest_message(topic)
|
150
|
-
end
|
151
|
-
|
152
|
-
def get_newest_message(topic)
|
153
|
-
@redis_pool.with do |redis|
|
154
|
-
result = redis.xrevrange(topic, count: 1)
|
155
|
-
return result[0]
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def self.get_last_offset(topic)
|
160
|
-
self.instance.get_last_offset(topic)
|
161
|
-
end
|
162
|
-
|
163
|
-
def get_last_offset(topic)
|
164
|
-
@redis_pool.with do |redis|
|
165
|
-
result = redis.xrevrange(topic, count: 1)
|
166
|
-
if result and result[0] and result[0][0]
|
167
|
-
result[0][0]
|
106
|
+
if result and result.length > 0
|
107
|
+
return result[0]
|
168
108
|
else
|
169
|
-
|
109
|
+
return nil
|
170
110
|
end
|
171
111
|
end
|
172
112
|
end
|
173
113
|
|
174
|
-
def
|
175
|
-
self.instance.read_topic_last(topic)
|
176
|
-
end
|
177
|
-
|
178
|
-
def read_topic_last(topic)
|
114
|
+
def get_newest_message(topic)
|
179
115
|
@redis_pool.with do |redis|
|
180
116
|
# Default in xrevrange is range end '+', start '-' which means get all
|
181
117
|
# elements from higher ID to lower ID and since we're limiting to 1
|
@@ -189,18 +125,15 @@ module Cosmos
|
|
189
125
|
end
|
190
126
|
end
|
191
127
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
def self.update_topic_offsets(topics)
|
203
|
-
self.instance.update_topic_offsets(topics)
|
128
|
+
def get_last_offset(topic)
|
129
|
+
@redis_pool.with do |redis|
|
130
|
+
result = redis.xrevrange(topic, count: 1)
|
131
|
+
if result and result[0] and result[0][0]
|
132
|
+
result[0][0]
|
133
|
+
else
|
134
|
+
"0-0"
|
135
|
+
end
|
136
|
+
end
|
204
137
|
end
|
205
138
|
|
206
139
|
def update_topic_offsets(topics)
|
@@ -221,15 +154,12 @@ module Cosmos
|
|
221
154
|
return offsets
|
222
155
|
end
|
223
156
|
|
224
|
-
def self.read_topics(topics, offsets = nil, timeout_ms = 1000, &block)
|
225
|
-
self.instance.read_topics(topics, offsets, timeout_ms, &block)
|
226
|
-
end
|
227
157
|
unless $enterprise_cosmos
|
228
|
-
def read_topics(topics, offsets = nil, timeout_ms = 1000)
|
158
|
+
def read_topics(topics, offsets = nil, timeout_ms = 1000, count = nil)
|
229
159
|
# Logger.debug "read_topics: #{topics}, #{offsets} pool:#{@redis_pool}"
|
230
160
|
@redis_pool.with do |redis|
|
231
161
|
offsets = update_topic_offsets(topics) unless offsets
|
232
|
-
result = redis.xread(topics, offsets, block: timeout_ms)
|
162
|
+
result = redis.xread(topics, offsets, block: timeout_ms, count: count)
|
233
163
|
if result and result.length > 0
|
234
164
|
result.each do |topic, messages|
|
235
165
|
messages.each do |msg_id, msg_hash|
|
@@ -244,26 +174,6 @@ module Cosmos
|
|
244
174
|
end
|
245
175
|
end
|
246
176
|
|
247
|
-
# Add new entry to the redis stream.
|
248
|
-
# > https://www.rubydoc.info/github/redis/redis-rb/Redis:xadd
|
249
|
-
#
|
250
|
-
# @example Without options
|
251
|
-
# COSMOS::Store().write_topic('MANGO__TOPIC', {'message' => 'something'})
|
252
|
-
# @example With options
|
253
|
-
# COSMOS::Store().write_topic('MANGO__TOPIC', {'message' => 'something'}, id: '0-0', maxlen: 1000, approximate: false)
|
254
|
-
#
|
255
|
-
# @param topic [String] the stream / topic
|
256
|
-
# @param msg_hash [Hash] one or multiple field-value pairs
|
257
|
-
#
|
258
|
-
# @option opts [String] :id the entry id, default value is `*`, it means auto generation
|
259
|
-
# @option opts [Integer] :maxlen max length of entries
|
260
|
-
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
261
|
-
#
|
262
|
-
# @return [String] the entry id
|
263
|
-
def self.write_topic(topic, msg_hash, id = '*', maxlen = nil, approximate = true)
|
264
|
-
self.instance.write_topic(topic, msg_hash, id, maxlen, approximate)
|
265
|
-
end
|
266
|
-
|
267
177
|
# Add new entry to the redis stream.
|
268
178
|
# > https://www.rubydoc.info/github/redis/redis-rb/Redis:xadd
|
269
179
|
#
|
@@ -289,23 +199,6 @@ module Cosmos
|
|
289
199
|
end
|
290
200
|
end
|
291
201
|
|
292
|
-
# Trims older entries of the redis stream if needed.
|
293
|
-
# > https://www.rubydoc.info/github/redis/redis-rb/Redis:xtrim
|
294
|
-
#
|
295
|
-
# @example Without options
|
296
|
-
# COSMOS::Store.trim_topic('MANGO__TOPIC', 1000)
|
297
|
-
# @example With options
|
298
|
-
# COSMOS::Store.trim_topic('MANGO__TOPIC', 1000, approximate: true, limit: 0)
|
299
|
-
#
|
300
|
-
# @param topic [String] the stream key
|
301
|
-
# @param minid [Integer] max length of entries to trim
|
302
|
-
# @param limit [Boolean] whether to add `~` modifier of maxlen or not
|
303
|
-
#
|
304
|
-
# @return [Integer] the number of entries actually deleted
|
305
|
-
def self.trim_topic(topic, minid, approximate = true, limit: 0)
|
306
|
-
self.instance.trim_topic(topic, minid, approximate, limit: limit)
|
307
|
-
end
|
308
|
-
|
309
202
|
# Trims older entries of the redis stream if needed.
|
310
203
|
# > https://www.rubydoc.info/github/redis/redis-rb/Redis:xtrim
|
311
204
|
#
|
@@ -325,6 +218,14 @@ module Cosmos
|
|
325
218
|
end
|
326
219
|
end
|
327
220
|
end
|
221
|
+
|
222
|
+
class EphemeralStore < Store
|
223
|
+
def initialize(pool_size = 10)
|
224
|
+
super(pool_size)
|
225
|
+
@redis_url = "redis://#{ENV['COSMOS_REDIS_EPHEMERAL_HOSTNAME']}:#{ENV['COSMOS_REDIS_EPHEMERAL_PORT']}"
|
226
|
+
@redis_pool = ConnectionPool.new(size: pool_size) { build_redis() }
|
227
|
+
end
|
228
|
+
end
|
328
229
|
end
|
329
230
|
|
330
231
|
class Redis
|
data/lib/cosmos/version.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
COSMOS_VERSION = '5.0.
|
3
|
+
COSMOS_VERSION = '5.0.4'
|
4
4
|
module Cosmos
|
5
5
|
module Version
|
6
6
|
MAJOR = '5'
|
7
7
|
MINOR = '0'
|
8
|
-
PATCH = '
|
8
|
+
PATCH = '4'
|
9
9
|
OTHER = ''
|
10
|
-
BUILD = '
|
10
|
+
BUILD = '84d6dcebd4bc21e5559963be4e5fde2ddb7e9822'
|
11
11
|
end
|
12
|
-
VERSION = '5.0.
|
13
|
-
GEM_VERSION = '5.0.
|
12
|
+
VERSION = '5.0.4'
|
13
|
+
GEM_VERSION = '5.0.4'
|
14
14
|
end
|