Skip to main content

What Is an Invoker?

Invokers are the engine that makes Contract fast. They’re pre-compiled method callers that let Contract call your service methods without the overhead of reflection on every request. Think of invokers like pre-addressed envelopes: instead of looking up the address every time you send a letter, you prepare the envelope once and just drop letters in it. When you register a service, Contract analyzes your methods using Go’s reflection system. This analysis happens once at startup, and the results are stored as β€œinvokers” - optimized callers that know exactly how to call each method.

Why Invokers Matter

Without invokers, calling a method by name would require reflection on every single request:
With invokers, the reflection cost is paid once at startup:

Basic Usage

Most of the time, you don’t interact with invokers directly - transports use them automatically behind the scenes. But understanding how they work helps you build custom transports or debugging tools.

Getting a Method and Its Invoker

Calling a Method via Its Invoker

The Invoker Interface

Invokers implement a simple interface that matches Contract’s method patterns:
Parameters: Returns:

Calling Different Method Types

Contract supports four method patterns. Here’s how to call each with invokers:

Method With Input and Output

This is the most common pattern:

Method With Output Only (No Input)

Method With Input Only (No Output)

Method With Neither Input Nor Output

Creating Input Instances Dynamically

Use NewInput() to create a new input instance for a method. This is essential when you don’t know the input type at compile time (like when building a transport):
This pattern is exactly what transports use: they create an input instance, unmarshal JSON into it, then call the invoker.

How Transports Use Invokers

Here’s simplified code showing how a transport uses invokers internally. This helps you understand what happens when a request comes in:

Transport Invoker

For building transports, there’s a higher-level interface called TransportInvoker that handles JSON unmarshaling:
Key difference from Invoker:
  • Invoker.Call() takes a parsed Go value as input
  • TransportInvoker.Invoke() takes raw JSON bytes and handles unmarshaling

Using the Default Transport Invoker

Creating a Custom Transport Invoker

You can wrap the default invoker to add logging, metrics, or other cross-cutting concerns:

Error Handling

Errors from your service method are returned directly through the invoker:

Context Handling

The context is passed directly to your method, preserving timeouts, cancellation, and values:

Type Safety

Always use type assertions when working with invoker results:

Building a Custom Transport

Here’s a complete example of using invokers to build a custom transport. This example creates a simple HTTP transport that takes the method name from a query parameter:
Usage:

Performance Characteristics

Understanding when operations are expensive helps you build efficient systems: Key insight: Heavy reflection happens once at startup. Runtime calls through invokers are as fast as regular function calls.

Common Patterns

Checking Method Capabilities

Iterating All Methods

Dynamic Method Dispatch

Useful for building generic tools that work with any service:

See Also