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: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:| Parameter | Type | Description |
|---|---|---|
ctx | context.Context | Request context (carries timeouts, cancellation signals, values) |
in | any | Input value (or nil for methods without input) |
| Return | Type | Description |
|---|---|---|
| result | any | Output value (or nil for methods without output) |
| err | error | Any error returned by your method |
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
UseNewInput() 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):
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 calledTransportInvoker that handles JSON unmarshaling:
Invoker.Call()takes a parsed Go value as inputTransportInvoker.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:Performance Characteristics
Understanding when operations are expensive helps you build efficient systems:| Operation | When | Cost |
|---|---|---|
| Reflection analysis | Registration (startup) | Slow, but only once |
| Invoker.Call() | Every request | Fast (direct function call) |
| Type assertion | Every request | Very fast |
| JSON parsing | Every request | Normal cost |
Common Patterns
Checking Method Capabilities
Iterating All Methods
Dynamic Method Dispatch
Useful for building generic tools that work with any service:See Also
- Registration - How invokers are created during registration
- Middleware - Wrapping invokers with middleware
- Architecture - Where invokers fit in the overall system