diff options
Diffstat (limited to 'app/services/clusters')
4 files changed, 110 insertions, 2 deletions
diff --git a/app/services/clusters/agent_tokens/create_service.rb b/app/services/clusters/agent_tokens/create_service.rb index 5b8a0e46a6c..2539ffdc5ba 100644 --- a/app/services/clusters/agent_tokens/create_service.rb +++ b/app/services/clusters/agent_tokens/create_service.rb @@ -30,13 +30,14 @@ module Clusters end def log_activity_event!(token) - token.agent.activity_events.create!( + Clusters::Agents::CreateActivityEventService.new( + token.agent, kind: :token_created, level: :info, recorded_at: token.created_at, user: current_user, agent_token: token - ) + ).execute end end end diff --git a/app/services/clusters/agent_tokens/track_usage_service.rb b/app/services/clusters/agent_tokens/track_usage_service.rb new file mode 100644 index 00000000000..fdc79ac0f8b --- /dev/null +++ b/app/services/clusters/agent_tokens/track_usage_service.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Clusters + module AgentTokens + class TrackUsageService + # The `UPDATE_USED_COLUMN_EVERY` defines how often the token DB entry can be updated + UPDATE_USED_COLUMN_EVERY = (40.minutes..55.minutes).freeze + + delegate :agent, to: :token + + def initialize(token) + @token = token + end + + def execute + track_values = { last_used_at: Time.current.utc } + + token.cache_attributes(track_values) + + if can_update_track_values? + log_activity_event!(track_values[:last_used_at]) unless agent.connected? + + # Use update_column so updated_at is skipped + token.update_columns(track_values) + end + end + + private + + attr_reader :token + + def can_update_track_values? + # Use a random threshold to prevent beating DB updates. + last_used_at_max_age = Random.rand(UPDATE_USED_COLUMN_EVERY) + + real_last_used_at = token.read_attribute(:last_used_at) + + # Handle too many updates from high token traffic + real_last_used_at.nil? || + (Time.current - real_last_used_at) >= last_used_at_max_age + end + + def log_activity_event!(recorded_at) + Clusters::Agents::CreateActivityEventService.new( + agent, + kind: :agent_connected, + level: :info, + recorded_at: recorded_at, + agent_token: token + ).execute + end + end + end +end diff --git a/app/services/clusters/agents/create_activity_event_service.rb b/app/services/clusters/agents/create_activity_event_service.rb new file mode 100644 index 00000000000..886dddf1a52 --- /dev/null +++ b/app/services/clusters/agents/create_activity_event_service.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Clusters + module Agents + class CreateActivityEventService + def initialize(agent, **params) + @agent = agent + @params = params + end + + def execute + agent.activity_events.create!(params) + + DeleteExpiredEventsWorker.perform_at(schedule_cleanup_at, agent.id) + + ServiceResponse.success + end + + private + + attr_reader :agent, :params + + def schedule_cleanup_at + 1.hour.from_now.change(min: agent.id % 60) + end + end + end +end diff --git a/app/services/clusters/agents/delete_expired_events_service.rb b/app/services/clusters/agents/delete_expired_events_service.rb new file mode 100644 index 00000000000..a0c0291c1fb --- /dev/null +++ b/app/services/clusters/agents/delete_expired_events_service.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Clusters + module Agents + class DeleteExpiredEventsService + def initialize(agent) + @agent = agent + end + + def execute + agent.activity_events + .recorded_before(remove_events_before) + .each_batch { |batch| batch.delete_all } + end + + private + + attr_reader :agent + + def remove_events_before + agent.activity_event_deletion_cutoff + end + end + end +end |