CI / CI (pull_request) Successful in 4m32s
- internal/temporal/client.go: robust client with retry + TLS + health check - internal/temporal/worker.go: worker creation, registration, lifecycle - internal/temporal/context.go: timeout helpers - k8s/worker-deployment.yaml: 2-10 replica HPA, health probes, security context - k8s/workflow-runner-deployment.yaml: singleton runner with probes - k8s/kustomization.yaml: updated resource list, removed missing ref Tests: 11 pass (client_test.go + worker_test.go) Build: go build ./... clean Kustomize: dry-run validated
111 lines
2.5 KiB
Go
111 lines
2.5 KiB
Go
// Package temporal provides Temporal SDK client initialization and management.
|
|
package temporal
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"time"
|
|
|
|
"go.temporal.io/sdk/client"
|
|
)
|
|
|
|
// ClientConfig extends TemporalConfig with SDK-specific options.
|
|
type ClientConfig struct {
|
|
HostPort string
|
|
Namespace string
|
|
TLSCert string
|
|
TLSKey string
|
|
DialTimeout time.Duration
|
|
MaxRetries int
|
|
IdentityPrefix string
|
|
}
|
|
|
|
// NewClient creates a new Temporal client with production-ready configuration.
|
|
//
|
|
// Features:
|
|
// - Automatic retry with exponential backoff
|
|
// - TLS support for secure communication
|
|
// - Connection pooling and health checks
|
|
// - Structured error reporting
|
|
func NewClient(cfg ClientConfig) (client.Client, error) {
|
|
if cfg.HostPort == "" {
|
|
cfg.HostPort = "temporal-frontend.temporal.svc.cluster.local:7233"
|
|
}
|
|
if cfg.Namespace == "" {
|
|
cfg.Namespace = "default"
|
|
}
|
|
if cfg.DialTimeout == 0 {
|
|
cfg.DialTimeout = 10 * time.Second
|
|
}
|
|
if cfg.MaxRetries == 0 {
|
|
cfg.MaxRetries = 3
|
|
}
|
|
if cfg.IdentityPrefix == "" {
|
|
cfg.IdentityPrefix = "poimen-worker"
|
|
}
|
|
|
|
var tlsConfig *tls.Config
|
|
if cfg.TLSCert != "" && cfg.TLSKey != "" {
|
|
cert, err := tls.LoadX509KeyPair(cfg.TLSCert, cfg.TLSKey)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load TLS credentials: %w", err)
|
|
}
|
|
tlsConfig = &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
}
|
|
}
|
|
|
|
clientOptions := client.Options{
|
|
HostPort: cfg.HostPort,
|
|
Namespace: cfg.Namespace,
|
|
Logger: nil, // Use default logger
|
|
}
|
|
|
|
if tlsConfig != nil {
|
|
clientOptions.ConnectionOptions = client.ConnectionOptions{
|
|
TLS: tlsConfig,
|
|
}
|
|
}
|
|
|
|
// Attempt to connect with retries
|
|
var c client.Client
|
|
var lastErr error
|
|
|
|
for attempt := 1; attempt <= cfg.MaxRetries; attempt++ {
|
|
var err error
|
|
c, err = client.Dial(clientOptions)
|
|
if err == nil {
|
|
return c, nil
|
|
}
|
|
lastErr = err
|
|
|
|
if attempt < cfg.MaxRetries {
|
|
backoff := time.Duration(1<<uint(attempt-1)) * time.Second
|
|
if backoff > 30*time.Second {
|
|
backoff = 30 * time.Second
|
|
}
|
|
time.Sleep(backoff)
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("failed to connect to Temporal after %d attempts: %w", cfg.MaxRetries, lastErr)
|
|
}
|
|
|
|
// HealthCheck verifies Temporal cluster connectivity.
|
|
func HealthCheck(c client.Client, timeout time.Duration) error {
|
|
ctx, cancel := ContextWithTimeout(timeout)
|
|
defer cancel()
|
|
|
|
req := &client.CheckHealthRequest{}
|
|
_, err := c.CheckHealth(ctx, req)
|
|
return err
|
|
}
|
|
|
|
// CloseClient safely closes the Temporal client.
|
|
func CloseClient(c client.Client) error {
|
|
if c != nil {
|
|
c.Close()
|
|
}
|
|
return nil
|
|
}
|