Docs / Contact / sdks/go/examples
Go SDK: Examples
Practical examples for common use cases with the Tendrl Go SDK.
Periodic Data Collection with Tether
The Tether method calls a function on a schedule and publishes its return value:
go
// Collect and publish system metrics every 30 seconds
stop := client.Tether("system-metrics", func() (interface{}, error) {
return map[string]interface{}{
"cpu_usage": getCPUUsage(),
"mem_usage": getMemUsage(),
"goroutines": runtime.NumGoroutine(),
}, nil
}, []string{"system", "metrics"}, 30*time.Second)
// Stop when done
defer stop()
Return an error to skip publishing that cycle without stopping the tether:
go
stop := client.Tether("sensor", func() (interface{}, error) {
value, err := readSensor()
if err != nil {
return nil, err // Skips this cycle, tries again next interval
}
return map[string]interface{}{"value": value}, nil
}, []string{"sensor"}, 5*time.Second)
Synchronous Publish with Response
Wait for the server to acknowledge a message:
go
messageID, err := client.Publish(
map[string]interface{}{
"action": "provision",
"device": "sensor-042",
},
[]string{"provisioning"},
"", // entity (empty = self)
true, // waitResponse
10, // timeout seconds
)
if err != nil {
log.Printf("Failed: %v", err)
} else {
log.Printf("Confirmed: %s", messageID)
}
Inbound Message Routing
Route incoming messages by tag with client.On():
go
client.On(tendrl.MessageRoute{
Tag: "diagnostic",
Handler: func(msg tendrl.IncomingMessage) error {
log.Println("Diagnostic:", msg.Data)
return nil
},
})
client.On(tendrl.MessageRoute{
Tag: "ai-response",
Handler: func(msg tendrl.IncomingMessage) error {
log.Println("AI:", msg.Data)
return nil
},
})
client.On(tendrl.MessageRoute{
Tags: []string{"alert", "anomaly"},
Handler: func(msg tendrl.IncomingMessage) error {
log.Println("Alert:", msg.Data)
return nil
},
})
client.SetMessageCheckRate(2 * time.Second)
client.SetMessageCheckLimit(10)
Cross-Account Messaging
Send messages to entities in other accounts:
go
err := client.PublishCrossAccount(
map[string]interface{}{
"command": "status_request",
},
"account123:us-west:entity:device-001",
[]string{"query"},
)
State Table Management
Persist device state that survives restarts:
go
// Read current state
state, err := client.GetState()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Current state: %v\n", state)
// Merge new data (PATCH; existing keys preserved)
err = client.UpdateState(map[string]interface{}{
"firmware": "2.1.0",
"last_boot": time.Now().Format(time.RFC3339),
}, nil)
// Merge with tags to trigger flows
err = client.UpdateState(map[string]interface{}{
"status": "active",
}, []string{"device", "status-change"})
// Replace entire state (PUT; removes all previous keys)
err = client.ReplaceState(map[string]interface{}{
"firmware": "2.1.0",
"status": "active",
}, nil)
Connectivity Monitoring
Check network status and react to changes:
go
if client.IsOnline() {
// Send queued data
client.PublishAsync(data, tags)
} else {
log.Println("Offline; message will be stored")
}
// Get detailed connectivity state
connState := client.GetConnectivityState()
fmt.Printf("Online: %v, Last check: %s\n",
connState.Online, connState.LastCheck)
Flexible Data Types
The SDK accepts any JSON-serializable type:
go
// Maps
client.PublishAsync(map[string]interface{}{"key": "value"}, tags)
// Structs
type SensorReading struct {
ID string `json:"id"`
Value float64 `json:"value"`
Unit string `json:"unit"`
}
client.PublishAsync(SensorReading{
ID: "temp-1", Value: 23.5, Unit: "celsius",
}, tags)
// Slices
client.PublishAsync([]int{1, 2, 3}, tags)
// Strings (auto-wrapped as {"data": "..."})
client.PublishAsync("simple message", tags)
// Primitives
client.PublishAsync(42, tags)
client.PublishAsync(3.14, tags)
client.PublishAsync(true, tags)
Custom Heartbeat
Send a manual heartbeat with specific metrics:
go
err := client.PublishHeartbeat(tendrl.HeartbeatData{
MemFree: getMemFree(),
MemTotal: getMemTotal(),
DiskFree: getDiskFree(),
DiskSize: getDiskTotal(),
})
Tendrl