Skip to content

gRPC Connector

The gRPC connector enables Meddle to invoke gRPC services as both a client reader (polling unary calls) and a writer (forwarding payloads as gRPC requests). It uses HTTP/2 under the hood and supports optional TLS, making it suitable for integrating with modern microservices, edge gateways, and industrial APIs that expose gRPC endpoints.

Connector Types:

  • GrpcReader - Periodically invokes a unary gRPC method and emits the response as a Meddle payload
  • GrpcWriter - Sends each incoming payload as a gRPC request to the target service
  • ✅ HTTP/2 transport with optional TLS encryption
  • ✅ Polling-based unary reader with configurable rate
  • ✅ Writer forwards payloads as JSON-encoded gRPC requests
  • ✅ Static request body for read polling
  • ✅ Streaming-aware configuration flag
  • ✅ Automatic connection management and reuse
  • ✅ Per-call 10-second timeout for safety
{
"type": "GrpcReader",
"config": {
"address": "192.168.1.50:50051",
"service": "iot.SensorService",
"method": "GetReading",
"pollingRate": 1000,
"requestBody": "{\"sensorId\":\"sensor-1\"}"
}
}
{
"type": "GrpcWriter",
"config": {
"address": "192.168.1.50:50051",
"service": "iot.SensorService",
"method": "PushReading",
"tls": false
}
}

The host and port of the gRPC server.

{
"address": "192.168.1.50:50051"
}

Format: host:port (no scheme prefix). For TLS endpoints, set tls: true rather than encoding it in the address.

The fully qualified gRPC service name as defined in your .proto file, including the package prefix.

{
"service": "iot.SensorService"
}

Format: package.ServiceName. The connector composes the full method path as /{service}/{method} internally.

The method name on the service to invoke.

{
"method": "GetReading"
}

This must match the method name exactly as declared in the proto definition (case-sensitive).

Enables TLS for the connection. When disabled, the connector uses insecure (plaintext) credentials.

{
"tls": true
}

Recommended values:

  • false - In-network, trusted environments (LAN/PLC)
  • true - Public endpoints, cloud services, anything crossing untrusted networks

Static JSON body sent as the request payload on every poll.

{
"requestBody": "{\"sensorId\":\"sensor-1\",\"includeHistory\":false}"
}

Notes:

  • Must be a valid JSON string. Escape inner quotes as shown
  • If omitted, an empty JSON object {} is sent
  • The request body is treated as a json.RawMessage and forwarded as-is on every poll

Interval in milliseconds between successive gRPC calls (reader only).

{
"pollingRate": 1000
}

Recommended values:

  • Fast: 100-500ms
  • Normal: 1000ms (1 second)
  • Slow: 5000ms+ (5 seconds or more)

Flag to indicate the target method uses server-streaming semantics.

{
"streaming": true
}

When set, the connector still issues calls on the polling cadence but tags the configuration as streaming-aware so downstream tooling can adapt expectations. Use this for methods that return progressively larger payloads or maintain a longer connection lifecycle.

gRPC Server → GrpcReader (unary invoke) → JSON response → Meddle Payload

Example:

Reader configuration:

{
"address": "192.168.1.50:50051",
"service": "iot.SensorService",
"method": "GetReading",
"requestBody": "{\"sensorId\":\"sensor-1\"}",
"pollingRate": 1000
}

Server response:

{
"temperature": 24.7,
"humidity": 58.3,
"battery": 0.91,
"timestamp": "2026-05-20T10:14:33Z"
}

Emitted Meddle payload:

{
"temperature": 24.7,
"humidity": 58.3,
"battery": 0.91,
"timestamp": "2026-05-20T10:14:33Z"
}
Meddle Payload → GrpcWriter (JSON encode) → gRPC Server

Example:

Incoming payload:

{
"deviceId": "plc-line-1",
"setpoint": 75.0,
"mode": "auto"
}

The writer JSON-encodes the payload and invokes /iot.SensorService/PushReading with it as the request body. Any response from the server is read and discarded.

Read sensor data from an internal microservice over the LAN:

{
"type": "GrpcReader",
"config": {
"address": "telemetry.internal:50051",
"service": "telemetry.DeviceService",
"method": "GetMetrics",
"pollingRate": 2000,
"requestBody": "{\"deviceId\":\"compressor-3\"}"
}
}

2. Pushing Aggregated Data to a Cloud gRPC Endpoint

Section titled “2. Pushing Aggregated Data to a Cloud gRPC Endpoint”

Forward processed payloads to a cloud service over TLS:

{
"type": "GrpcWriter",
"config": {
"address": "api.example.cloud:443",
"service": "ingest.MetricsService",
"method": "Push",
"tls": true
}
}

3. Edge-to-Edge Communication Between Meddle Instances

Section titled “3. Edge-to-Edge Communication Between Meddle Instances”

Bridge two Meddle deployments using gRPC as the transport:

{
"type": "GrpcWriter",
"config": {
"address": "edge-aggregator.local:50052",
"service": "meddle.BridgeService",
"method": "Forward",
"tls": false
}
}

Problem: connection refused or transport: error while dialing

Solutions:

  1. Verify the address and port are correct
  2. Confirm the gRPC server is running and listening
  3. Check firewall rules (telnet host port for a quick reachability test)
  4. If the server requires TLS, set tls: true

Problem: rpc error: code = Unimplemented or unknown method

Solutions:

  1. Verify the service is the fully qualified name including the package (e.g. iot.SensorService, not just SensorService)
  2. Confirm the method matches the proto declaration exactly (case-sensitive)
  3. Use a tool like grpcurl to list services on the endpoint:
    Terminal window
    grpcurl -plaintext 192.168.1.50:50051 list

Problem: Deserialization error on the server

Solutions:

  1. Validate that requestBody is well-formed JSON
  2. Ensure the field names match the proto field names exactly (gRPC-JSON transcoding is case-sensitive)
  3. If your server expects protobuf binary, gRPC-JSON transcoding (or grpc-gateway) must be enabled server-side

Problem: TLS handshake or certificate errors

Solutions:

  1. Confirm the server certificate is valid and trusted
  2. Ensure the address hostname matches the certificate’s SAN
  3. For self-signed certificates, install the CA into the trust store of the Meddle host

Problem: Repeated 10-second timeouts on every call

Solutions:

  1. Investigate server-side latency
  2. If the response is consistently slow, the unary 10s timeout is a hard ceiling — consider a streaming method or a different transport
  3. Reduce pollingRate to avoid stacking calls behind slow responses

1. Always Use TLS Outside Trusted Networks

Section titled “1. Always Use TLS Outside Trusted Networks”

Never leave tls: false for endpoints that traverse the public internet:

{
"tls": true
}

A 100ms poll against a remote gRPC server can saturate downstream rate limits. Start at 1000ms and tighten only when justified.

Prefer services with explicit .proto contracts and versioned packages (e.g. iot.v1.SensorService) so reader configs don’t break on server upgrades.

Inline requestBody is great for static parameters but a poor fit for dynamic values. For dynamic request bodies, pair an upstream Reshape or Transform connector with a GrpcWriter instead of a reader.

Always feed gRPC responses through a Validation connector before downstream writers, since server schemas may evolve faster than your Meddle pipeline.

GrpcReader → Validation → Reshape → InfluxDb2Writer
  1. GrpcReader: Polls /iot.SensorService/GetReading every second
  2. Validation: Ensures required keys are present and numeric
  3. Reshape: Adds tags such as location, device_type
  4. InfluxDb2Writer: Stores in a time-series database
ModbusReader → Filter → GrpcWriter (cloud ingest)
  1. ModbusReader: Pulls register values from a PLC at 1s cadence
  2. Filter: Keeps only the keys to forward
  3. GrpcWriter: Pushes the filtered payload to a cloud ingest.MetricsService.Push method over TLS
  • HTTP Client - Alternative for REST/HTTP services
  • MQTTv5 - Asynchronous broker-based integration
  • Kafka - High-throughput streaming alternative
  • Validation - Validate gRPC response payloads
  • Reshape - Rename and enrich fields from gRPC responses