Skip to content

Feat: Enhance service method retrieval and invocation features#1429

Open
Similarityoung wants to merge 10 commits intoapache:developfrom
Similarityoung:feature/generic
Open

Feat: Enhance service method retrieval and invocation features#1429
Similarityoung wants to merge 10 commits intoapache:developfrom
Similarityoung:feature/generic

Conversation

@Similarityoung
Copy link

Description

This PR adds structured service method introspection and generic invoke capabilities to Dubbo Admin console, and tightens the generic invoke contract to rely on provider metadata instead of client-supplied parameter types.

What changed

  • Added console APIs for service method discovery:

    • GET /api/v1/service/methods

    • GET /api/v1/service/method/detail

    • POST /api/v1/service/generic/invoke

  • Extended method detail response to include:

    • signature

    • method-related types closure derived from provider metadata

  • Changed generic invoke request contract:

    • removed client-provided parameterTypes

    • added signature

    • backend now resolves authoritative parameterTypes from provider metadata by service + methodName + signature

  • Added stricter overload handling:

    • if signature is omitted and the method is overloaded, return InvalidArgument

    • if only fallback metadata exists without structured Methods/Types, return a clear error instead of guessing

  • Refactored generic invoke argument decoding:

    • switched request args to []json.RawMessage

    • decode values after metadata resolution based on target parameter types

    • supports numeric primitives, primitive arrays, object arrays, JVM array descriptors, and char

  • Included a small ZK governor compatibility fix when creating nodes


To help us figure out who should review this PR, please put an X in all the areas that this PR affects.

  • Docs

  • Installation

  • User Experience

  • Dubboctl

  • Console

  • Core Component

Copilot AI review requested due to automatic review settings March 8, 2026 09:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds service method introspection endpoints and a metadata-driven generic invocation flow to the Dubbo Admin console, shifting generic invoke parameter type resolution from client input to provider metadata.

Changes:

  • Added console APIs for listing service methods, fetching method details (including signature/types closure), and performing generic invoke.
  • Implemented provider-metadata-based overload resolution via methodName + signature and refactored generic invoke argument decoding using []json.RawMessage.
  • Updated ZK node creation flag usage and bumped/adjusted Go module dependencies to support the new generic invoke implementation.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/governor/zk/governor.go Adjusts ZK node creation flags for compatibility.
pkg/console/service/service_generic_invoke_decode.go Adds typed argument decoding helpers for generic invoke based on resolved parameter types.
pkg/console/service/service_generic_invoke.go Implements generic invoke flow: metadata lookup, overload resolution, target selection, and RPC invocation.
pkg/console/service/service.go Adds provider-metadata-backed method discovery and method detail/type-closure building.
pkg/console/router/router.go Registers new service routes for methods, method detail, and generic invoke under /api/v1/service.
pkg/console/model/service.go Adds request/response models for method discovery, method detail, and generic invoke (including signature and raw args).
pkg/console/handler/service.go Adds handlers wiring the new endpoints to service layer functions.
go.mod Updates dubbo-go dependency and adds hessian2 + other indirects needed for new invoke path.
go.sum Updates dependency checksums accordingly.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +59 to +84
var invokeGenericServiceRPC = func(callCtx context.Context, invocation genericInvocation) (any, error) {
ins, err := dubbo.NewInstance(dubbo.WithName(genericInvokeInstanceName))
if err != nil {
return nil, err
}

cli, err := ins.NewClient(
client.WithClientProtocolTriple(),
client.WithClientSerialization(dubboconstant.Hessian2Serialization),
)
if err != nil {
return nil, err
}

svc, err := cli.NewGenericService(
invocation.ServiceName,
client.WithURL(invocation.URL),
client.WithVersion(invocation.Version),
client.WithGroup(invocation.Group),
)
if err != nil {
return nil, err
}

return svc.Invoke(callCtx, invocation.MethodName, invocation.ParameterTypes, invocation.Args)
}
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invokeGenericServiceRPC creates a new Dubbo instance + client + generic service on every invocation. This is likely expensive and may also accumulate background resources (connections, goroutines) depending on the dubbo-go implementation. Consider initializing and reusing a singleton instance/client (and, if possible, a cached generic service per service/version/group) with proper lifecycle management instead of rebuilding everything per request.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimization can be made in the future

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copilot这里说的有道理,这里可以在代码里记一个todo,加上client的缓存

@Similarityoung
Copy link
Author


Code review

Found 1 issue:

  1. Generic invoke leaks raw upstream/internal RPC errors back to the client instead of following the console's usual stable InternalError pattern. The rest of pkg/console/service returns fixed user-facing messages and logs the cause server-side, but this new path returns err.Error() directly, which can expose transport/provider details and make API responses inconsistent.

if err != nil {
logger.Errorf("generic invoke failed, service=%s, method=%s, providerApp=%s, target=%s:%d, cause: %v",
req.ServiceName, req.MethodName, providerAppName, target.instance.Spec.Ip, target.port, err)
return nil, bizerror.New(bizerror.InternalError, err.Error())
}

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.


Copy link
Contributor

@robocanic robocanic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great Work! I left some comments and hope you can discuss them with me.

}

func (s *ServiceGenericInvokeReq) Validate() error {
s.Mesh = strings.TrimSpace(s.Mesh)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestrion: 这里都可以简化用lancet的工具类strutil.isBlank来判断

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix

return filtered, nil
}

func matchesServiceMethodsReq(metadata *meshresource.ServiceProviderMetadataResource, req model.ServiceMethodsReq) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion:这里的过滤其实可以在查询DB的时候做掉。可以在ServiceProviderMetadata的index(pkg/core/store/index/service_provider_metadata.go)里面新增对于serviceKey(serviceName:version:group)的一个索引,这样就不用在上层过滤了。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix

}
}

for methodName := range fallbackMethodNames {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question:这段逻辑有点没看懂,可以写写注释

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前实现会优先使用 Spec.Methods 里的结构化定义;只有当结构化方法信息缺失时,才退回到 parameters["methods"] 里提取方法名做兜底展示,避免 fallback 覆盖掉更完整的签名/参数类型信息。

return nil, err
}

cli, err := ins.NewClient(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question:这里是不是应该根据目标service的协议和序列化来new client?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里其他协议我还没做测试,我记得序列化好像只有 Hessian2,我回头看看。

Comment on lines +59 to +84
var invokeGenericServiceRPC = func(callCtx context.Context, invocation genericInvocation) (any, error) {
ins, err := dubbo.NewInstance(dubbo.WithName(genericInvokeInstanceName))
if err != nil {
return nil, err
}

cli, err := ins.NewClient(
client.WithClientProtocolTriple(),
client.WithClientSerialization(dubboconstant.Hessian2Serialization),
)
if err != nil {
return nil, err
}

svc, err := cli.NewGenericService(
invocation.ServiceName,
client.WithURL(invocation.URL),
client.WithVersion(invocation.Version),
client.WithGroup(invocation.Group),
)
if err != nil {
return nil, err
}

return svc.Invoke(callCtx, invocation.MethodName, invocation.ParameterTypes, invocation.Args)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copilot这里说的有道理,这里可以在代码里记一个todo,加上client的缓存

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 8, 2026

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

Successfully merging this pull request may close these issues.

3 participants