[Feature][Triple][Generic] Expose Triple response attachments for generic invocations
- Dominant language
- Go
- Stars
- 5k
- Forks
- 1k
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 31
Description
### Problem
Dubbo-go already supports passing request attachments through `context.WithValue(ctx, constant.AttachmentKey, ...)`. The `dubbo-go-samples/context` sample covers this direction:
```text
consumer request attachment -> provider ctx.Value(constant.AttachmentKey) -> business response body
```
However, this does not cover the opposite direction:
```text
provider result attachments -> Triple response trailers -> consumer reads response attachments
```
For Triple unary calls, provider-side result attachments can be propagated as response trailers. The missing piece is that generic invocations do not currently expose a consumer-side API for reading those response trailers.
### Current limitation
`filter/generic.GenericService` currently defines `Invoke` as a function field without per-call options:
```go
type GenericService struct {
Invoke func(ctx context.Context, methodName string, types []string, args []hessian.Object) (any, error) `dubbo:"$invoke"`
}
```
The normal Triple generated unary client path can capture response metadata with call options, for example:
```go
var trailers http.Header
resp, err := svc.Greet(
ctx,
req,
client.WithResponseTrailer(&trailers),
)
```
But `GenericService.Invoke` has no `opts ...client.CallOption` parameter, so callers cannot pass `client.WithResponseTrailer(&trailers)` when making a generic invocation.
### Expected behavior
Generic Triple unary invocations should provide a way to read response attachments/trailers on the consumer side.
One possible API shape:
```go
var trailers http.Header
result, err := genericService.Invoke(
ctx,
"echo",
[]string{"java.lang.String"},
[]hessian.Object{"hello"},
client.WithResponseTrailer(&trailers),
)
```
`InvokeWithType` should also be able to pass the same call options through:
```go
err := genericService.InvokeWithType(
ctx,
"getUser",
[]string{"java.lang.String"},
[]hessian.Object{"123"},
&user,
client.WithResponseTrailer(&trailers),
)
```
### Suggested implementation direction
- Add `opts ...client.CallOption` to `GenericService.Invoke` and `InvokeWithType`.
- Teach the proxy reflection path to recognize and strip optional `client.CallOption` values from the service method arguments.
- Preserve those call options when constructing the invocation, using the same response metadata attribute path as generated unary clients (`ResponseHeaderKey` / `ResponseTrailerKey`).
- Avoid introducing a second mechanism that reads response trailers back from the original `context.Context`; the existing unary client call option path should be reused.
### Why this matters
Without this, the request attachment path is usable, but generic callers cannot read provider response attachments from Triple response trailers. Documentation should describe the supported direction clearly, and the generic API should expose the same response metadata capture capability available to generated unary clients.
Contributor guide
Research direction
Start with filter/generic.GenericService and trace the proxy reflection path that builds generic invocation arguments. Check how generated Triple unary clients use ResponseHeaderKey, ResponseTrailerKey, and client.CallOption; done means Invoke and InvokeWithType accept the options and a generic consumer can read provider response trailers without using a second context mechanism.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100