openc3 7.0.1 → 7.1.1
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/openc3cli +50 -3
- data/data/config/interface_modifiers.yaml +3 -1
- data/data/config/item_modifiers.yaml +1 -1
- data/data/config/microservice.yaml +15 -2
- data/data/config/parameter_modifiers.yaml +49 -7
- data/data/config/plugins.yaml +1 -0
- data/data/config/target.yaml +11 -0
- data/data/config/target_config.yaml +6 -2
- data/lib/openc3/api/api.rb +1 -0
- data/lib/openc3/api/calendar_api.rb +183 -0
- data/lib/openc3/api/cmd_api.rb +2 -1
- data/lib/openc3/api/metrics_api.rb +11 -1
- data/lib/openc3/api/tlm_api.rb +21 -6
- data/lib/openc3/core_ext/faraday.rb +1 -1
- data/lib/openc3/io/json_api.rb +1 -1
- data/lib/openc3/logs/log_writer.rb +3 -1
- data/lib/openc3/microservices/decom_common.rb +128 -0
- data/lib/openc3/microservices/decom_microservice.rb +30 -97
- data/lib/openc3/microservices/interface_decom_common.rb +6 -2
- data/lib/openc3/microservices/interface_microservice.rb +10 -8
- data/lib/openc3/microservices/log_microservice.rb +1 -1
- data/lib/openc3/microservices/microservice.rb +3 -2
- data/lib/openc3/microservices/queue_microservice.rb +1 -1
- data/lib/openc3/microservices/scope_cleanup_microservice.rb +60 -46
- data/lib/openc3/microservices/text_log_microservice.rb +1 -2
- data/lib/openc3/models/cvt_model.rb +24 -13
- data/lib/openc3/models/db_sharded_model.rb +110 -0
- data/lib/openc3/models/interface_model.rb +9 -0
- data/lib/openc3/models/interface_status_model.rb +33 -3
- data/lib/openc3/models/metric_model.rb +96 -37
- data/lib/openc3/models/microservice_model.rb +7 -0
- data/lib/openc3/models/microservice_status_model.rb +30 -3
- data/lib/openc3/models/plugin_model.rb +20 -8
- data/lib/openc3/models/queue_model.rb +36 -46
- data/lib/openc3/models/reingest_job_model.rb +153 -0
- data/lib/openc3/models/scope_model.rb +3 -2
- data/lib/openc3/models/script_status_model.rb +4 -20
- data/lib/openc3/models/target_model.rb +113 -100
- data/lib/openc3/models/trigger_model.rb +1 -1
- data/lib/openc3/packets/packet_config.rb +4 -1
- data/lib/openc3/packets/parsers/xtce_parser.rb +23 -1
- data/lib/openc3/script/script.rb +6 -4
- data/lib/openc3/script/script_runner.rb +4 -4
- data/lib/openc3/script/telemetry.rb +3 -3
- data/lib/openc3/script/web_socket_api.rb +29 -22
- data/lib/openc3/system/system.rb +20 -3
- data/lib/openc3/topics/command_decom_topic.rb +4 -2
- data/lib/openc3/topics/command_topic.rb +9 -5
- data/lib/openc3/topics/decom_interface_topic.rb +15 -10
- data/lib/openc3/topics/interface_topic.rb +71 -29
- data/lib/openc3/topics/limits_event_topic.rb +62 -41
- data/lib/openc3/topics/router_topic.rb +61 -21
- data/lib/openc3/topics/system_events_topic.rb +18 -1
- data/lib/openc3/topics/telemetry_decom_topic.rb +3 -1
- data/lib/openc3/topics/telemetry_topic.rb +4 -2
- data/lib/openc3/topics/topic.rb +77 -5
- data/lib/openc3/utilities/aws_bucket.rb +2 -0
- data/lib/openc3/utilities/cli_generator.rb +10 -2
- data/lib/openc3/utilities/metric.rb +15 -1
- data/lib/openc3/utilities/questdb_client.rb +173 -37
- data/lib/openc3/utilities/reingest_job.rb +377 -0
- data/lib/openc3/utilities/ruby_lex_utils.rb +2 -0
- data/lib/openc3/utilities/running_script.rb +8 -10
- data/lib/openc3/utilities/store_autoload.rb +78 -52
- data/lib/openc3/utilities/store_queued.rb +20 -12
- data/lib/openc3/version.rb +5 -5
- data/templates/microservice/microservices/TEMPLATE/microservice.py +9 -0
- data/templates/plugin/plugin.gemspec +13 -1
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +3 -3
- data/templates/tool_vue/src/router.js +2 -2
- data/templates/widget/package.json +2 -2
- metadata +8 -3
|
@@ -158,12 +158,12 @@ module OpenC3
|
|
|
158
158
|
variables[current_variable_name]['description'] = params[0]
|
|
159
159
|
when 'VARIABLE_STATE'
|
|
160
160
|
usage = "#{keyword} <Display Text> <Value>"
|
|
161
|
-
parser.verify_num_parameters(
|
|
161
|
+
parser.verify_num_parameters(1, 2, usage)
|
|
162
162
|
unless current_variable_name
|
|
163
163
|
raise "VARIABLE_STATE must follow a VARIABLE definition"
|
|
164
164
|
end
|
|
165
165
|
variables[current_variable_name]['options'] ||= []
|
|
166
|
-
option = { 'value' => params[1], 'text' => params[0] }
|
|
166
|
+
option = { 'value' => params[1] || params[0], 'text' => params[0] }
|
|
167
167
|
variables[current_variable_name]['options'] << option
|
|
168
168
|
end
|
|
169
169
|
end
|
|
@@ -229,12 +229,13 @@ module OpenC3
|
|
|
229
229
|
plugin_model.homepage = pkg.spec.homepage
|
|
230
230
|
plugin_model.repository = pkg.spec.metadata['source_code_uri'] # this key because it's in the official gemspec examples
|
|
231
231
|
plugin_model.keywords = pkg.spec.metadata['openc3_store_keywords']&.split(/, ?/)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
# Resolve the plugin's store image path. The gemspec generated by
|
|
233
|
+
# `cli generate plugin` sets `openc3_store_image` to `public/store_img.png`
|
|
234
|
+
# but does not create that file, so we must verify existence regardless
|
|
235
|
+
# of whether the path came from metadata or the default — otherwise the
|
|
236
|
+
# frontend hits a 500 when fetching the missing file.
|
|
237
|
+
img_path = pkg.spec.metadata['openc3_store_image'] || 'public/store_img.png'
|
|
238
|
+
img_path = nil unless File.exist?(File.join(gem_path, img_path))
|
|
238
239
|
package_name = "#{pkg.spec.name}-#{pkg.spec.version}"
|
|
239
240
|
plugin_model.img_path = File.join('gems', package_name, img_path) if img_path # convert this filesystem path to volumes mount path
|
|
240
241
|
plugin_model.update() unless validate_only
|
|
@@ -525,5 +526,16 @@ module OpenC3
|
|
|
525
526
|
end
|
|
526
527
|
return result.sort
|
|
527
528
|
end
|
|
529
|
+
|
|
530
|
+
# Remove the backing gem for an unloaded plugin so it disappears from
|
|
531
|
+
# GemModel.names (and the admin Packages tab). Skips the removal if any
|
|
532
|
+
# other PluginModel (any scope, any counter) still references the gem,
|
|
533
|
+
# via the existing PluginModel.gem_names check inside GemModel.destroy.
|
|
534
|
+
def self.cleanup_gem(plugin_name, scope:)
|
|
535
|
+
gem_filename = plugin_name.split("__")[0]
|
|
536
|
+
OpenC3::GemModel.destroy(gem_filename, log_and_raise_needed_errors: false)
|
|
537
|
+
rescue => e
|
|
538
|
+
Logger.warn("Could not remove gem #{gem_filename}: #{e.message}", scope: scope)
|
|
539
|
+
end
|
|
528
540
|
end
|
|
529
541
|
end
|
|
@@ -44,34 +44,37 @@ module OpenC3
|
|
|
44
44
|
model = get_model(name: name, scope: scope)
|
|
45
45
|
raise QueueError, "Queue '#{name}' not found in scope '#{scope}'" unless model
|
|
46
46
|
|
|
47
|
-
if model.state
|
|
48
|
-
result = Store.zrevrange("#{scope}:#{name}", 0, 0, with_scores: true)
|
|
49
|
-
if result.empty?
|
|
50
|
-
id = 1.0
|
|
51
|
-
else
|
|
52
|
-
id = result[0][1].to_f + 1
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Build command data with support for both formats
|
|
56
|
-
command_data = { username: username, timestamp: Time.now.to_nsec_from_epoch, validate: validate, timeout: timeout }
|
|
57
|
-
if target_name && cmd_name
|
|
58
|
-
# New format: store target_name, cmd_name, and cmd_params separately
|
|
59
|
-
command_data[:target_name] = target_name
|
|
60
|
-
command_data[:cmd_name] = cmd_name
|
|
61
|
-
command_data[:cmd_params] = JSON.generate(cmd_params.as_json, allow_nan: true) if cmd_params
|
|
62
|
-
elsif command
|
|
63
|
-
# Legacy format: store command string for backwards compatibility
|
|
64
|
-
command_data[:value] = command
|
|
65
|
-
else
|
|
66
|
-
raise QueueError, "Must provide either command string or target_name/cmd_name parameters"
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
Store.zadd("#{scope}:#{name}", id, command_data.to_json)
|
|
70
|
-
model.notify(kind: 'command')
|
|
71
|
-
else
|
|
47
|
+
if model.state == 'DISABLE'
|
|
72
48
|
error_msg = command || "#{target_name} #{cmd_name}"
|
|
73
49
|
raise QueueError, "Queue '#{name}' is disabled. Command '#{error_msg}' not queued."
|
|
74
50
|
end
|
|
51
|
+
|
|
52
|
+
result = Store.zrevrange("#{scope}:#{name}", 0, 0, with_scores: true)
|
|
53
|
+
id = result.empty? ? 1.0 : result[0][1].to_f + 1
|
|
54
|
+
|
|
55
|
+
command_data = build_command_data(username: username, command: command, target_name: target_name,
|
|
56
|
+
cmd_name: cmd_name, cmd_params: cmd_params, validate: validate, timeout: timeout)
|
|
57
|
+
Store.zadd("#{scope}:#{name}", id, command_data.to_json)
|
|
58
|
+
model.notify(kind: 'command')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Build the hash that gets serialized into Redis. Always uses symbol keys so
|
|
62
|
+
# downstream code in this class can access values consistently. cmd_params is
|
|
63
|
+
# JSON-encoded as a string so binary data survives the round-trip via as_json.
|
|
64
|
+
def self.build_command_data(username:, command: nil, target_name: nil, cmd_name: nil, cmd_params: nil, validate: nil, timeout: nil)
|
|
65
|
+
command_data = { username: username, timestamp: Time.now.to_nsec_from_epoch }
|
|
66
|
+
if target_name && cmd_name
|
|
67
|
+
command_data[:target_name] = target_name
|
|
68
|
+
command_data[:cmd_name] = cmd_name
|
|
69
|
+
command_data[:cmd_params] = JSON.generate(cmd_params.as_json, allow_nan: true) if cmd_params
|
|
70
|
+
elsif command
|
|
71
|
+
command_data[:value] = command
|
|
72
|
+
else
|
|
73
|
+
raise QueueError, "Must provide either command string or target_name/cmd_name parameters"
|
|
74
|
+
end
|
|
75
|
+
command_data[:validate] = validate unless validate.nil?
|
|
76
|
+
command_data[:timeout] = timeout unless timeout.nil?
|
|
77
|
+
command_data
|
|
75
78
|
end
|
|
76
79
|
|
|
77
80
|
attr_accessor :name, :state
|
|
@@ -115,49 +118,36 @@ module OpenC3
|
|
|
115
118
|
QueueTopic.write_notification(notification, scope: @scope)
|
|
116
119
|
end
|
|
117
120
|
|
|
118
|
-
def insert_command(id,
|
|
121
|
+
def insert_command(id: nil, username:, command: nil, target_name: nil, cmd_name: nil, cmd_params: nil, validate: nil, timeout: nil)
|
|
119
122
|
if @state == 'DISABLE'
|
|
120
|
-
|
|
121
|
-
command_name = command_data['value']
|
|
122
|
-
else
|
|
123
|
-
command_name = "#{command_data['target_name']} #{command_data['cmd_name']}"
|
|
124
|
-
end
|
|
123
|
+
command_name = command || "#{target_name} #{cmd_name}"
|
|
125
124
|
raise QueueError, "Queue '#{@name}' is disabled. Command '#{command_name}' not queued."
|
|
126
125
|
end
|
|
127
126
|
|
|
128
127
|
unless id
|
|
129
128
|
result = Store.zrevrange("#{@scope}:#{@name}", 0, 0, with_scores: true)
|
|
130
|
-
|
|
131
|
-
id = 1.0
|
|
132
|
-
else
|
|
133
|
-
id = result[0][1].to_f + 1
|
|
134
|
-
end
|
|
129
|
+
id = result.empty? ? 1.0 : result[0][1].to_f + 1
|
|
135
130
|
end
|
|
136
131
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
command_data['cmd_params'] = JSON.generate(command_data['cmd_params'].as_json, allow_nan: true)
|
|
140
|
-
end
|
|
132
|
+
command_data = self.class.build_command_data(username: username, command: command, target_name: target_name,
|
|
133
|
+
cmd_name: cmd_name, cmd_params: cmd_params, validate: validate, timeout: timeout)
|
|
141
134
|
Store.zadd("#{@scope}:#{@name}", id, command_data.to_json)
|
|
142
135
|
notify(kind: 'command')
|
|
143
136
|
end
|
|
144
137
|
|
|
145
|
-
def update_command(id:,
|
|
138
|
+
def update_command(id:, username:, command: nil, target_name: nil, cmd_name: nil, cmd_params: nil, validate: nil, timeout: nil)
|
|
146
139
|
if @state == 'DISABLE'
|
|
147
140
|
raise QueueError, "Queue '#{@name}' is disabled. Command at id #{id} not updated."
|
|
148
141
|
end
|
|
149
142
|
|
|
150
|
-
# Check if command exists at the given id
|
|
151
143
|
existing = Store.zrangebyscore("#{@scope}:#{@name}", id, id)
|
|
152
144
|
if existing.empty?
|
|
153
145
|
raise QueueError, "No command found at id #{id} in queue '#{@name}'"
|
|
154
146
|
end
|
|
155
147
|
|
|
156
|
-
# Remove the existing command and add the new one at the same id
|
|
157
148
|
Store.zremrangebyscore("#{@scope}:#{@name}", id, id)
|
|
158
|
-
command_data =
|
|
159
|
-
|
|
160
|
-
command_data[:timeout] = timeout unless timeout.nil?
|
|
149
|
+
command_data = self.class.build_command_data(username: username, command: command, target_name: target_name,
|
|
150
|
+
cmd_name: cmd_name, cmd_params: cmd_params, validate: validate, timeout: timeout)
|
|
161
151
|
Store.zadd("#{@scope}:#{@name}", id, command_data.to_json)
|
|
162
152
|
notify(kind: 'command')
|
|
163
153
|
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 OpenC3, Inc.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is distributed in the hope that it will be useful,
|
|
7
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
8
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
# See LICENSE.md for more details.
|
|
10
|
+
#
|
|
11
|
+
# This file may also be used under the terms of a commercial license
|
|
12
|
+
# if purchased from OpenC3, Inc.
|
|
13
|
+
|
|
14
|
+
require 'openc3/models/model'
|
|
15
|
+
|
|
16
|
+
module OpenC3
|
|
17
|
+
# Tracks one run of OpenC3::ReingestJob. The job updates this record from a
|
|
18
|
+
# background thread; the storage_controller status endpoint reads it.
|
|
19
|
+
# `updated_at` doubles as the heartbeat — if a Running record hasn't been
|
|
20
|
+
# touched in STALE_THRESHOLD_SEC, the status endpoint surfaces it as 'Stale'.
|
|
21
|
+
class ReingestJobModel < Model
|
|
22
|
+
PRIMARY_KEY = 'openc3_reingest_job'
|
|
23
|
+
STALE_THRESHOLD_SEC = 60
|
|
24
|
+
|
|
25
|
+
STATES = %w[Queued Running Complete Crashed Stale].freeze
|
|
26
|
+
PHASES = %w[downloading enabling_dedup ingesting dedup_cooldown disabling_dedup].freeze
|
|
27
|
+
|
|
28
|
+
attr_accessor :state
|
|
29
|
+
attr_accessor :files
|
|
30
|
+
attr_accessor :bucket
|
|
31
|
+
attr_accessor :path
|
|
32
|
+
attr_accessor :table_names
|
|
33
|
+
attr_accessor :target_version
|
|
34
|
+
attr_accessor :versions_used
|
|
35
|
+
attr_accessor :warnings
|
|
36
|
+
attr_accessor :progress_phase
|
|
37
|
+
attr_accessor :progress_current
|
|
38
|
+
attr_accessor :progress_total
|
|
39
|
+
attr_accessor :packets_written
|
|
40
|
+
attr_accessor :dedup_enabled_by_us
|
|
41
|
+
attr_accessor :dedup_preexisting
|
|
42
|
+
attr_accessor :dedup_disabled_tables
|
|
43
|
+
attr_accessor :dedup_cooldown_seconds
|
|
44
|
+
attr_accessor :dedup_enabled_at
|
|
45
|
+
attr_accessor :dedup_disabled_at
|
|
46
|
+
attr_accessor :error
|
|
47
|
+
attr_accessor :started_at
|
|
48
|
+
attr_accessor :finished_at
|
|
49
|
+
|
|
50
|
+
def self.get(name:, scope:)
|
|
51
|
+
super("#{scope}__#{PRIMARY_KEY}", name: name)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.names(scope:)
|
|
55
|
+
super("#{scope}__#{PRIMARY_KEY}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.all(scope:)
|
|
59
|
+
all = super("#{scope}__#{PRIMARY_KEY}")
|
|
60
|
+
all.sort_by { |_key, value| value['updated_at'] }.reverse
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def initialize(
|
|
64
|
+
name:,
|
|
65
|
+
state: 'Queued',
|
|
66
|
+
files: [],
|
|
67
|
+
bucket: nil,
|
|
68
|
+
path: nil,
|
|
69
|
+
table_names: [],
|
|
70
|
+
target_version: 'as_logged',
|
|
71
|
+
versions_used: [],
|
|
72
|
+
warnings: [],
|
|
73
|
+
progress_phase: nil,
|
|
74
|
+
progress_current: 0,
|
|
75
|
+
progress_total: 0,
|
|
76
|
+
packets_written: 0,
|
|
77
|
+
dedup_enabled_by_us: [],
|
|
78
|
+
dedup_preexisting: [],
|
|
79
|
+
dedup_disabled_tables: [],
|
|
80
|
+
dedup_cooldown_seconds: 60,
|
|
81
|
+
dedup_enabled_at: nil,
|
|
82
|
+
dedup_disabled_at: nil,
|
|
83
|
+
error: nil,
|
|
84
|
+
started_at: nil,
|
|
85
|
+
finished_at: nil,
|
|
86
|
+
updated_at: nil,
|
|
87
|
+
plugin: nil,
|
|
88
|
+
scope:
|
|
89
|
+
)
|
|
90
|
+
super("#{scope}__#{PRIMARY_KEY}", name: name, updated_at: updated_at, plugin: plugin, scope: scope)
|
|
91
|
+
@state = state
|
|
92
|
+
@files = files
|
|
93
|
+
@bucket = bucket
|
|
94
|
+
@path = path
|
|
95
|
+
@table_names = table_names
|
|
96
|
+
@target_version = target_version
|
|
97
|
+
@versions_used = versions_used
|
|
98
|
+
@warnings = warnings
|
|
99
|
+
@progress_phase = progress_phase
|
|
100
|
+
@progress_current = progress_current
|
|
101
|
+
@progress_total = progress_total
|
|
102
|
+
@packets_written = packets_written
|
|
103
|
+
@dedup_enabled_by_us = dedup_enabled_by_us
|
|
104
|
+
@dedup_preexisting = dedup_preexisting
|
|
105
|
+
@dedup_disabled_tables = dedup_disabled_tables
|
|
106
|
+
@dedup_cooldown_seconds = dedup_cooldown_seconds
|
|
107
|
+
@dedup_enabled_at = dedup_enabled_at
|
|
108
|
+
@dedup_disabled_at = dedup_disabled_at
|
|
109
|
+
@error = error
|
|
110
|
+
@started_at = started_at
|
|
111
|
+
@finished_at = finished_at
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# True if state is Running but the heartbeat (updated_at) is older than
|
|
115
|
+
# STALE_THRESHOLD_SEC. Callers should surface state as 'Stale' in that case.
|
|
116
|
+
def stale?
|
|
117
|
+
return false unless @state == 'Running'
|
|
118
|
+
return false unless @updated_at
|
|
119
|
+
age_nsec = Time.now.to_nsec_from_epoch - @updated_at.to_i
|
|
120
|
+
age_nsec > STALE_THRESHOLD_SEC * 1_000_000_000
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def as_json(*_a)
|
|
124
|
+
{
|
|
125
|
+
'name' => @name,
|
|
126
|
+
'state' => stale? ? 'Stale' : @state,
|
|
127
|
+
'files' => @files,
|
|
128
|
+
'bucket' => @bucket,
|
|
129
|
+
'path' => @path,
|
|
130
|
+
'table_names' => @table_names,
|
|
131
|
+
'target_version' => @target_version,
|
|
132
|
+
'versions_used' => @versions_used,
|
|
133
|
+
'warnings' => @warnings,
|
|
134
|
+
'progress_phase' => @progress_phase,
|
|
135
|
+
'progress_current' => @progress_current,
|
|
136
|
+
'progress_total' => @progress_total,
|
|
137
|
+
'packets_written' => @packets_written,
|
|
138
|
+
'dedup_enabled_by_us' => @dedup_enabled_by_us,
|
|
139
|
+
'dedup_preexisting' => @dedup_preexisting,
|
|
140
|
+
'dedup_disabled_tables' => @dedup_disabled_tables,
|
|
141
|
+
'dedup_cooldown_seconds' => @dedup_cooldown_seconds,
|
|
142
|
+
'dedup_enabled_at' => @dedup_enabled_at,
|
|
143
|
+
'dedup_disabled_at' => @dedup_disabled_at,
|
|
144
|
+
'error' => @error,
|
|
145
|
+
'started_at' => @started_at,
|
|
146
|
+
'finished_at' => @finished_at,
|
|
147
|
+
'updated_at' => @updated_at,
|
|
148
|
+
'plugin' => @plugin,
|
|
149
|
+
'scope' => @scope,
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -389,8 +389,9 @@ module OpenC3
|
|
|
389
389
|
end
|
|
390
390
|
|
|
391
391
|
# Delete the topics we created for the scope
|
|
392
|
-
|
|
393
|
-
Topic.del("#{@scope}
|
|
392
|
+
db_shard = Store.db_shard_for_target('UNKNOWN', scope: @scope)
|
|
393
|
+
Topic.del("#{@scope}__COMMAND__{UNKNOWN}__UNKNOWN", db_shard: db_shard)
|
|
394
|
+
Topic.del("#{@scope}__TELEMETRY__{UNKNOWN}__UNKNOWN", db_shard: db_shard)
|
|
394
395
|
Topic.del("#{@scope}__openc3_targets")
|
|
395
396
|
Topic.del("#{@scope}__CONFIG")
|
|
396
397
|
end
|
|
@@ -66,17 +66,9 @@ module OpenC3
|
|
|
66
66
|
keys = self.store.zrevrange("#{RUNNING_PRIMARY_KEY}__#{scope}__LIST", offset.to_i, offset.to_i + limit.to_i - 1)
|
|
67
67
|
return [] if keys.empty?
|
|
68
68
|
result = []
|
|
69
|
-
|
|
70
|
-
# No pipelining for cluster mode
|
|
71
|
-
# because it requires using the same shard for all keys
|
|
69
|
+
result = self.store.redis_pool.pipelined do
|
|
72
70
|
keys.each do |key|
|
|
73
|
-
|
|
74
|
-
end
|
|
75
|
-
else
|
|
76
|
-
result = self.store.redis_pool.pipelined do
|
|
77
|
-
keys.each do |key|
|
|
78
|
-
self.store.hget("#{RUNNING_PRIMARY_KEY}__#{scope}", key)
|
|
79
|
-
end
|
|
71
|
+
self.store.hget("#{RUNNING_PRIMARY_KEY}__#{scope}", key)
|
|
80
72
|
end
|
|
81
73
|
end
|
|
82
74
|
result = result.map do |r|
|
|
@@ -91,17 +83,9 @@ module OpenC3
|
|
|
91
83
|
keys = self.store.zrevrange("#{COMPLETED_PRIMARY_KEY}__#{scope}__LIST", offset.to_i, offset.to_i + limit.to_i - 1)
|
|
92
84
|
return [] if keys.empty?
|
|
93
85
|
result = []
|
|
94
|
-
|
|
95
|
-
# No pipelining for cluster mode
|
|
96
|
-
# because it requires using the same shard for all keys
|
|
86
|
+
result = self.store.redis_pool.pipelined do
|
|
97
87
|
keys.each do |key|
|
|
98
|
-
|
|
99
|
-
end
|
|
100
|
-
else
|
|
101
|
-
result = self.store.redis_pool.pipelined do
|
|
102
|
-
keys.each do |key|
|
|
103
|
-
self.store.hget("#{COMPLETED_PRIMARY_KEY}__#{scope}", key)
|
|
104
|
-
end
|
|
88
|
+
self.store.hget("#{COMPLETED_PRIMARY_KEY}__#{scope}", key)
|
|
105
89
|
end
|
|
106
90
|
end
|
|
107
91
|
result = result.map do |r|
|