Skip to content

Commit 926c3c3

Browse files
committed
Add specs and implement more runtime status stuff
1 parent a6947fa commit 926c3c3

File tree

10 files changed

+83
-27
lines changed

10 files changed

+83
-27
lines changed

app/graphql/types/runtime_status_type.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class RuntimeStatusType < Types::BaseObject
88
null: false,
99
description: 'The detailed configuration entries for this runtime status (only for adapters)',
1010
method: :runtime_status_configurations
11-
field :feature_set, [String], null: false, description: 'The set of features supported by the runtime'
11+
field :features, [String], null: false, description: 'The set of features supported by the runtime'
1212
field :identifier, String, null: false, description: 'The unique identifier for this runtime status'
1313
field :last_heartbeat, Types::TimeType, null: true,
1414
description: 'The timestamp of the last heartbeat received from the runtime'

app/grpc/flow_handler.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ class FlowHandler < Tucana::Sagittarius::FlowService::Service
88
grpc_stream :update
99

1010
def self.update_runtime(runtime)
11+
runtime.last_heartbeat = Time.zone.now
12+
runtime.save!
13+
1114
flows = []
1215
runtime.project_assignments.compatible.each do |assignment|
1316
assignment.namespace_project.flows.each do |flow|

app/grpc/runtime_status_handler.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ def update(request, _call)
88
current_runtime = Runtime.find(Code0::ZeroTrack::Context.current[:runtime][:id])
99

1010
response = Runtimes::Grpc::RuntimeStatusUpdateService.new(
11-
current_runtime,
12-
request.status
11+
runtime: current_runtime,
12+
status_info: request.send(request.status)
1313
).execute
1414

1515
logger.debug("RuntimeFunctionHandler#update response: #{response.inspect}")

app/services/error_code.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def self.error_codes
8888
invalid_node_parameter: { description: 'The node parameter is invalid' },
8989
invalid_node_function: { description: 'The node function is invalid' },
9090
invalid_runtime_status: { description: 'The runtime status is invalid because of active model errors' },
91+
invalid_runtime_status_configuration: { description: 'The runtime status configuration is invalid because of active model errors' },
9192

9293
primary_level_not_found: { description: '', deprecation_reason: 'Outdated concept' },
9394
secondary_level_not_found: { description: '', deprecation_reason: 'Outdated concept' },

app/services/runtimes/grpc/runtime_status_update_service.rb

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module Runtimes
44
module Grpc
55
class RuntimeStatusUpdateService
66
include Sagittarius::Database::Transactional
7+
include Code0::ZeroTrack::Loggable
78

89
attr_reader :runtime, :status_info
910

@@ -24,45 +25,37 @@ def execute
2425
)
2526
end
2627

27-
db_status = RuntimeStatus.find_or_initialize_by(runtime: current_runtime,
28+
db_status = RuntimeStatus.find_or_initialize_by(runtime: runtime,
2829
identifier: status_info.identifier)
2930

30-
db_status.last_heartbeat = Time.zone.at(status_info.last_heartbeat.seconds)
31+
db_status.last_heartbeat = Time.zone.at(status_info.timestamp.to_i)
3132
db_status.status_type = if status_info.is_a?(Tucana::Shared::AdapterRuntimeStatus)
3233
:adapter
3334
else
3435
:execution
3536
end
36-
db_status.feature_set = status_info.feature_set.to_a
37+
db_status.features = status_info.features.to_a
3738

38-
case status_info.status
39-
when Tucana::Shared::Status::NOT_RESPONDING
40-
db_status.status = :not_responding
41-
when Tucana::Shared::Status::NOT_READY
42-
db_status.status = :not_ready
43-
when Tucana::Shared::Status::RUNNING
44-
db_status.status = :running
45-
when Tucana::Shared::Status::STOPPED
46-
db_status.status = :stopped
47-
else
48-
logger.error("Unknown status received: #{status_info.status}")
49-
t.rollback_and_return ServiceResponse.error(
50-
message: 'Unknown status received',
51-
error_code: :invalid_runtime_status,
52-
details: { status: status_info.status }
53-
)
54-
end
39+
db_status.status = status_info.status.downcase
5540

5641
db_configs = db_status.runtime_status_configurations.first(status_info.configurations.size)
5742

5843
status_info.configurations.each_with_index do |config, index|
5944
db_configs[index] ||= db_status.runtime_status_configurations.build
6045

6146
db_configs[index].endpoint = config.endpoint
47+
48+
next if db_configs[index].save
49+
50+
t.rollback_and_return! ServiceResponse.error(
51+
message: 'Failed to save runtime status configuration',
52+
error_code: :invalid_runtime_status_configuration,
53+
details: db_configs.errors
54+
)
6255
end
6356

6457
unless db_status.save
65-
t.rollback_and_return ServiceResponse.error(
58+
t.rollback_and_return! ServiceResponse.error(
6659
message: 'Failed to save runtime status',
6760
error_code: :invalid_runtime_status,
6861
details: db_status.errors

db/migrate/20251216161818_add_detailed_runtime_status.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def change
1111
t.integer :status_type, null: false, default: 0
1212
t.datetime_with_timezone :last_heartbeat
1313
t.text :identifier, null: false
14-
t.text :feature_set, array: true, default: [], null: false
14+
t.text :features, array: true, default: [], null: false
1515

1616
t.timestamps_with_timezone
1717
end

db/structure.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ CREATE TABLE runtime_statuses (
748748
status_type integer DEFAULT 0 NOT NULL,
749749
last_heartbeat timestamp with time zone,
750750
identifier text NOT NULL,
751-
feature_set text[] DEFAULT '{}'::text[] NOT NULL,
751+
features text[] DEFAULT '{}'::text[] NOT NULL,
752752
created_at timestamp with time zone NOT NULL,
753753
updated_at timestamp with time zone NOT NULL
754754
);

lib/sagittarius/middleware/grpc/logger.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def execute(method:, **_)
3131
end_time = Sagittarius::Utils.monotonic_time
3232
payload = log_payload(method, code, end_time - start_time, exception)
3333

34+
p exception.backtrace
3435
if exception
3536
logger.error(**payload, stack: exception.backtrace)
3637
else

spec/factories/runtime_status.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
last_heartbeat { Time.zone.today }
77
status_type { :adapter }
88
identifier { SecureRandom.uuid }
9-
feature_set { [] }
9+
features { [] }
1010
runtime
1111
end
1212
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe 'sagittarius.RuntimeStatusServiceRuntimeFunctionDefinitionService', :need_grpc_server do
6+
include GrpcHelpers
7+
8+
let(:stub) { create_stub Tucana::Sagittarius::RuntimeStatusService }
9+
10+
describe 'Update' do
11+
let(:runtime) { create(:runtime) }
12+
let(:to_update_status) do
13+
Tucana::Shared::AdapterRuntimeStatus.new(
14+
status: Tucana::Shared::RuntimeStatus::RUNNING,
15+
timestamp: Time.now.to_i.to_s,
16+
identifier: 'adapter_status_1',
17+
features: ['http'],
18+
configurations: [
19+
Tucana::Shared::AdapterConfiguration.new(
20+
endpoint: 'http://localhost:3000'
21+
)
22+
]
23+
)
24+
end
25+
26+
let(:message) do
27+
Tucana::Sagittarius::RuntimeStatusUpdateRequest.new(adapter_runtime_status: to_update_status)
28+
end
29+
30+
it 'creates a correct functions' do
31+
expect(stub.update(message, authorization(runtime)).success).to be(true)
32+
db_status = RuntimeStatus.last
33+
expect(db_status.runtime).to eq(runtime)
34+
expect(db_status.identifier).to eq('adapter_status_1')
35+
expect(db_status.status_type).to eq('adapter')
36+
expect(db_status.status).to eq('running')
37+
expect(db_status.features).to eq(['http'])
38+
expect(db_status.runtime_status_configurations.count).to eq(1)
39+
expect(db_status.runtime_status_configurations.first.endpoint).to eq('http://localhost:3000')
40+
end
41+
42+
context 'when old configuration exists before' do
43+
before do
44+
create(:runtime_status_configuration, endpoint: 'http://old-endpoint.com',
45+
runtime_status: create(:runtime_status,
46+
runtime: runtime,
47+
identifier: 'adapter_status_1'))
48+
end
49+
50+
it 'updates the existing configuration' do
51+
expect(stub.update(message, authorization(runtime)).success).to be(true)
52+
expect(RuntimeStatusConfiguration.count).to eq(1)
53+
config = RuntimeStatusConfiguration.last
54+
expect(config.endpoint).to eq('http://localhost:3000')
55+
end
56+
end
57+
end
58+
end

0 commit comments

Comments
 (0)