googleapis / gax-ruby

Google API Extensions for Ruby
https://rubygems.org/gems/google-gax
BSD 3-Clause "New" or "Revised" License
20 stars 22 forks source link

Update metadata handling and add block to expose grpc ops internally #118

Closed jbolinger closed 6 years ago

jbolinger commented 6 years ago

This is a WIP for a potential new toolkit feature. The main goal is to invoke all internal grpc calls using the return_op=true flag so that any additional grpc information is available and can be trapped in gax, via an optional block. Those blocks will then be used by the generated gapic methods to trap and expose things like response metadata to the caller.

Related toolkit change: https://github.com/googleapis/toolkit/pull/1865

Note: Do not merge until the feature is finalized!

codecov-io commented 6 years ago

Codecov Report

Merging #118 into master will increase coverage by 0.01%. The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #118      +/-   ##
==========================================
+ Coverage   99.48%   99.49%   +0.01%     
==========================================
  Files          19       19              
  Lines        1937     1990      +53     
==========================================
+ Hits         1927     1980      +53     
  Misses         10       10
Impacted Files Coverage Δ
lib/google/gax/settings.rb 99% <100%> (+0.03%) :arrow_up:
spec/google/gax/api_callable_spec.rb 98.43% <100%> (+0.31%) :arrow_up:
lib/google/gax/api_callable.rb 98.43% <100%> (+0.09%) :arrow_up:
spec/google/gax/settings_spec.rb 100% <100%> (ø) :arrow_up:

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 19306ce...243231c. Read the comment docs.

landrito commented 6 years ago

Interesting! Can you provide an example of how a user would use this feature?

jbolinger commented 6 years ago

Yes, sorry I meant to do that but forgot!

So, the end user would do something like this:

output = client.batch_annotate_images(
    [{
         image: {
             source: { image_uri: "gs://gapic-toolkit/President_Barack_Obama.jpg" }
         },
         features: [{ type: :FACE_DETECTION }]
     }],
    options: Google::Gax::CallOptions.new(metadata: { 'x-some-header' => 'some value' })
  )

puts "output is: #{output}"
puts "response metadata are: #{client.last_response_headers}"

The GAPIC layer will be modified to do something like this:

def batch_annotate_images requests, options: nil
    req = {
      requests: requests
    }.delete_if { |_, v| v.nil? }
    req = Google::Gax::to_proto(req, Google::Cloud::Vision::V1::BatchAnnotateImagesRequest)
    @batch_annotate_images.call(req, options) { |op| @last_response_headers = op.metadata }
end
jbolinger commented 6 years ago

I'd also like to enable the following, or something similar, but have to think it through a little more so we don't break the old way and it's consistent with the other APIs

client.batch_annotate_images(...) do | response, metadata |
   # do stuff with the result...
done
geigerj commented 6 years ago

I still think that passing return_op: true for every gRPC call, including the majority of calls where we don't care about the trailers and just retrieve the operation result, seems ugly. But per offline discussion, I won't block the review over it.

Just for confirmation, @apolcyn -- is there any downside to our libraries setting return_op: true and blocking on the result for calls where we don't actually need the operation, as opposed to not setting return_op?

apolcyn commented 6 years ago

Just for confirmation, @apolcyn -- is there any downside to our libraries setting return_op: true and blocking on the result for calls where we don't actually need the operation, as opposed to not setting return_op?

Once the RPC has been started, the behavior of return_op: true, and return_op: false will be the same. return_op true effectively just allows splitting up instantiation and RPC invocation, and effectively just gives a different surface API.

jbolinger commented 6 years ago

@geigerj @landrito - not super urgent, but bumping so we can get this merged relatively soon.

Any outstanding concerns? The only issue I can recall is if we wanted to return nil when a block was passed to prevent exposing the same thing through the block and the return value. I don't really have an opinion either way. Thoughts? I miss anything else?

geigerj commented 6 years ago

I was just waiting for a resolution to the question about on permitting both blocks and return values, and two other minor threads:

jbolinger commented 6 years ago

Let's leave the warning out for now since it's documented - we can add it later per your suggestion.

I haven't found a better way for the mocks. Happy to update if someone has a suggestion though.

That just leaves us with the return issue. I don't have a strong opinion either way. I'm sort of inclined to leave it as-is simply because I found it useful for dev purposes (makes it easy to dump the server response to the console while doing other things in the block). Granted, that is a bit bizarre and I'm 100% willing to change it to return nil if there is any strong opinion to do so.

geigerj commented 6 years ago

@jbolinger -- before you merge, could you check my comment on paginated calls here: https://github.com/googleapis/gax-ruby/pull/118/files#diff-30f305d8fc0cc5476762707ed876f556L229?

jbolinger commented 6 years ago

Will do. I wanted to test that against a live API but haven't gotten to it. Can you think of a good one (not logging)?

geigerj commented 6 years ago

@jbolinger you could try Pub/Sub. I think if you use the gapic-test project, there are already some test resources (i.e., subscriptions/topics/messages) set up for you to run against.