Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support accessing trailing_metadata in unary functions #1856

Closed
@daniel-sanche

Description

@daniel-sanche

Most grpc calls return a grpc.Call object containing trailing metadata and other useful information. This object is exposed to gapic users in streaming rpcs, because it is part of the iterator object that is returned when the rpc is called. Unary gapic methods don't currently expose this in any way, so there is no way to access trailing metadata without going around gapic

There are a few ways we could surface the grpc.Call object:

Synchronous

Option 1.

We can expose this in synchronous methods through a separete *_with_call method, which returns a tuple of the result data, and the Call object. This would align us with how the underlying grpc library handles the issue.

result = client.read_row()
result, call_data = client.read_row_with_call()

Option 2

Alternatively, we could expose this through a callback that is passed in, if we want to keep the result type static

def on_complete(call):
  print(call)

result = client.read_row(grpc_call_callback=on_complete)

Either way, implementing this requires this change in the api-core repo (Merged)

Async

Option 1

One way to address this is to return the Call object directly, instead of awaiting it as part of the function. This would force us to change all of our function signatures from "coroutine functions" into "sync functions that return a coroutine", but functionally it should be the same. (This is already how we handle the stream methods)

# from
async def read_rows(*args, **kwargs):
  return await rpc(*args, **kwargs)

# to
def read_rows(*args, **kwargs):
  return rpc(*args, **kwargs)

Option 2

Alternatively, we could follow the same format we choose for the Synchronous surface, to keep things consistent (i.e. either returning a tuple when a flag is set, or accepting a callback)

A callback could be a bit tricky convenient for async functions though, because we need to be an an async context to access any useful information on the Call object

result, call = await client.read_row(with_call=True)

or

async def on_complete(call):
  print(call)

result = await client.read_row(grpc_call_callback=on_complete)

or

def on_complete(call, metadata, status):
  print(call)

result = await client.read_row(grpc_call_callback=on_complete)

or

future = asyncio.Future()
result = await client.read_row(grpc_call_future=future)
call_data = await future

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: p2Moderately-important priority. Fix may not be included in next release.type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions