summaryrefslogtreecommitdiff
path: root/lib/gitlab/gitaly_client/call.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/gitaly_client/call.rb')
-rw-r--r--lib/gitlab/gitaly_client/call.rb72
1 files changed, 72 insertions, 0 deletions
diff --git a/lib/gitlab/gitaly_client/call.rb b/lib/gitlab/gitaly_client/call.rb
new file mode 100644
index 00000000000..9d4d86997ad
--- /dev/null
+++ b/lib/gitlab/gitaly_client/call.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GitalyClient
+ class Call
+ def initialize(storage, service, rpc, request, remote_storage, timeout)
+ @storage = storage
+ @service = service
+ @rpc = rpc
+ @request = request
+ @remote_storage = remote_storage
+ @timeout = timeout
+ @duration = 0
+ end
+
+ def call(&block)
+ response = recording_request do
+ GitalyClient.execute(@storage, @service, @rpc, @request, remote_storage: @remote_storage, timeout: @timeout, &block)
+ end
+
+ if response.is_a?(Enumerator)
+ # When the given response is an enumerator (coming from streamed
+ # responses), we wrap it in order to properly measure the stream
+ # consumption as it happens.
+ #
+ # store_timings is not called in that scenario as needs to be
+ # handled lazily in the custom Enumerator context.
+ instrument_stream(response)
+ else
+ store_timings
+ response
+ end
+ rescue => err
+ store_timings
+ raise err
+ end
+
+ private
+
+ def instrument_stream(response)
+ Enumerator.new do |yielder|
+ loop do
+ value = recording_request { response.next }
+
+ yielder.yield(value)
+ end
+ ensure
+ store_timings
+ end
+ end
+
+ def recording_request
+ start = Gitlab::Metrics::System.monotonic_time
+
+ yield
+ ensure
+ @duration += Gitlab::Metrics::System.monotonic_time - start
+ end
+
+ def store_timings
+ GitalyClient.add_query_time(@duration)
+
+ return unless Gitlab::PerformanceBar.enabled_for_request?
+
+ request_hash = @request.is_a?(Google::Protobuf::MessageExts) ? @request.to_h : {}
+
+ GitalyClient.add_call_details(feature: "#{@service}##{@rpc}", duration: @duration, request: request_hash, rpc: @rpc,
+ backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller))
+ end
+ end
+ end
+end