Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could this gem support client_interceptors? #25

Open
yakjuly opened this issue Sep 10, 2024 · 2 comments
Open

Could this gem support client_interceptors? #25

yakjuly opened this issue Sep 10, 2024 · 2 comments

Comments

@yakjuly
Copy link

yakjuly commented Sep 10, 2024

GrpcMock gem works great, only one thing concerned us is in our system, we use client_interceptors and track log as events.

GrpcMock only mock the request response but skipped interceptors.

https://github.com/ganmacs/grpc_mock/blob/master/lib/grpc_mock/grpc_stub_adapter.rb#L22

            operation = call.operation
            operation.define_singleton_method(:execute) do
              mock.evaluate(request, call.single_req_view)
            end
            operation

and https://github.com/grpc/grpc/blob/master/src/ruby/lib/grpc/generic/client_stub.rb#L173

        op.define_singleton_method(:execute) do
          interception_context.intercept!(:request_response, intercept_args) do
            c.request_response(req, metadata: metadata)
          end
        end

After compared above code, I can see it misses interception_context.intercept!(:request_response, intercept_args)
Is there a plan to support interecept for this gem? Thank you!

@ganmacs
Copy link
Owner

ganmacs commented Sep 16, 2024

we use client_interceptors and track log as events.

Could you explain the use case? This gem is used for mocking gRPC responses in tests, but I’m not sure why interceptors are needed."

@yakjuly
Copy link
Author

yakjuly commented Sep 16, 2024

Hi @ganmacs . In my project, I need to persist all gRPC API request/response in database.
My implementation is to use client interceptor. The code is similar to this.

class LogInterceptor < ::GRPC::ClientInterceptor

    def request_response(request: nil, call: nil, method: nil, metadata: {}, &block)
      notify(request, method, call, metadata, &block)
    end

    private

    def notify(request, method, _call, metadata)
      code = ::GRPC::Core::StatusCodes::OK
      start_time = Time.now
      response = yield
    rescue StandardError => e
      code = e.is_a?(::GRPC::BadStatus) ? e.code : ::GRPC::Core::StatusCodes::UNKNOWN

      raise
    ensure
      response_time = Time.now
      payload = {
        metadata: metadata,
        rpc_method: method,
        request: request.to_h,
        response: response.to_h,
        response_code: code,
        request_time: start_time,
        response_time: response_time,
        duration: (response_time - start_time)
      }

      payload[:exception] = e.message if e
      ActiveSupport::Notifications.instrument("grpc_transaction.#{method}", payload)
    end
  end

# Before GPRC request
@client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure, interceptors: [LogInterceptor.new])

# In Rails initializer, to decouple the persist logic
ActiveSupport::Notifications.subscribe(/grpc_transaction/) do |name, start, finish, id, payload|
  notification = { name:, start:, finish:, payload: }
  GrpcRequestTracker.add_log_event(notification)
end

The idea is wrap some logic in the API transaction lifecycle, similar to a rack middleware.

In rspec and cucumber tests, I want to confirm the log was persisted. If I use GrpcMock.stub_request(/a_service/a_rpc_method).to_return(fake_response). It does not execute interceptor logic, because the grpc_stub_adapter skips block interception_context.intercept!(:request_response, intercept_args) do

That's why I would like this gem to support client interceptors, so that I don't have to write a walk around solution like mock a real grpc server in a thread.

I created a PR to contribute this feature #26
Please let me know if this use case make sense to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants