# Temporal gRPC Integration - Migration Status ## Overview Temporal REST ↔ gRPC bridge is being implemented. Client sends HTTP JSON → gateway translates to gRPC → Temporal server responds. ## Implementation Status ### Phase 1: Core Workflow Operations ✅ WIRED - **START_WORKFLOW** ✅ gRPC: `StartWorkflowExecution` - **DESCRIBE_WORKFLOW** ✅ gRPC: `DescribeWorkflowExecution` - **LIST_WORKFLOWS** ⏳ TODO (requires pagination logic) - **GET_WORKFLOW_HISTORY** ⏳ TODO - **SIGNAL_WORKFLOW** ⏳ TODO - **QUERY_WORKFLOW** ⏳ TODO - **CANCEL_WORKFLOW** ⏳ TODO - **TERMINATE_WORKFLOW** ⏳ TODO - **RESET_WORKFLOW** ⏳ TODO - **UPDATE_WORKFLOW** ⏳ TODO ### Phase 2: Activity Operations ⏳ NOT IMPLEMENTED - HEARTBEAT_ACTIVITY - COMPLETE_ACTIVITY - FAIL_ACTIVITY **Note:** Activity operations require different error handling (task tokens, etc.). See operations_grpc.go for reference. ### Phase 3: OperatorService Operations ⏳ NOT IMPLEMENTED Requires separate gRPC stub. Currently: - LIST_NAMESPACES → 501 NOT_IMPLEMENTED - DESCRIBE_NAMESPACE → 501 NOT_IMPLEMENTED - CREATE_NAMESPACE → 501 NOT_IMPLEMENTED - UPDATE_NAMESPACE → 501 NOT_IMPLEMENTED - DELETE_NAMESPACE → 501 NOT_IMPLEMENTED - LIST_SEARCH_ATTRIBUTES → 501 NOT_IMPLEMENTED - ADD_SEARCH_ATTRIBUTES → 501 NOT_IMPLEMENTED - LIST_TASK_QUEUES → 501 NOT_IMPLEMENTED - GET_CLUSTER_INFO → 501 NOT_IMPLEMENTED - LIST_CLUSTER_MEMBERS → 501 NOT_IMPLEMENTED - GET_SYSTEM_INFO → 501 NOT_IMPLEMENTED ## Architecture ``` HTTP Request (JSON) ↓ Handler.startWorkflow() ↓ Converts to protobuf (workflowservice.StartWorkflowExecutionRequest) ↓ gRPCClient.GetWorkflowServiceStub().StartWorkflowExecution(ctx, req) ↓ Temporal Server (port 7233) ↓ gRPC Response ↓ Convert to JSON response map ↓ HTTP 200 JSON ``` ## Code References - **handler.go**: HTTP ↔ gRPC translation layer - `NewHandler()`: Creates gRPC connection via `NewGRPCClient()` - `startWorkflow()`, `describeWorkflow()`: gRPC-wired operations - Others: stubs or NOT_IMPLEMENTED - **grpc_client.go**: Low-level gRPC connection management - `NewGRPCClient()`: Dials Temporal at port 7233 - `GetWorkflowServiceStub()`: Returns `workflowservice.WorkflowServiceClient` - `GetOperatorServiceStub()`: Returns `operatorservice.OperatorServiceClient` - **operations_grpc.go**: Example gRPC implementations (reference for wiring) - Shows payload marshaling patterns - Shows error handling (gRPC status codes → HTTP 4xx/5xx) ## Next Steps (Phase 2) 1. Wire remaining WorkflowService operations (LIST, GET_HISTORY, SIGNAL, QUERY, etc.) - All use same pattern: build protobuf request → call stub → map response to JSON - Reference operations_grpc.go for exact patterns 2. Add OperatorService support (namespaces, cluster, search attrs) - Create separate stub: `operatorServiceClient := NewGRPCClient().GetOperatorServiceStub()` - Add methods to handler for each operation 3. Add Activity operations (heartbeat, complete, fail) - Requires task token handling - See operations_grpc_test.go for test patterns ## Build Status ``` go build ./cmd/gateway ✅ SUCCESS ``` ## Testing To test gRPC wiring locally: ```bash # Start Temporal locally (if not running) docker run -d -p 7233:7233 temporalio/auto-setup:latest # Start gateway go run ./cmd/gateway # Test (in another terminal) curl -X POST http://localhost:8080/workflow \ -H 'Content-Type: application/json' \ -d '{ "action": "START_WORKFLOW", "namespace": "default", "payload": { "workflow_id": "test-1", "workflow_type": "MyWorkflow", "task_queue": "my-queue" } }' # Should return { "success": true, "action": "START_WORKFLOW", "data": { "workflow_id": "test-1", "run_id": "abc123...", "start_time": "2026-08-27T..." } } ``` ## Key Implementation Details ### Protobuf Field Names Temporal protobuf uses snake_case field names: - `WorkflowId` not `WorkflowID` - `RunId` not `RunID` - `WorkflowType` (message) not `WorkflowTypeString` - `TaskQueue` (message) not `TaskQueueName` ### Type Imports (from go.temporal.io/api) ```go import ( "go.temporal.io/api/common/v1" // WorkflowExecution, WorkflowType, Payloads "go.temporal.io/api/taskqueue/v1" // TaskQueue "go.temporal.io/api/workflowservice/v1" // All Workflow* stubs "go.temporal.io/api/operatorservice/v1" // Namespace/cluster stubs (not yet used) ) ``` ### Payload Marshaling Pattern ```go input := getMap(payload, "input") if len(input) > 0 { inputBytes, _ := json.Marshal(input) req.Input = &common.Payloads{ Payloads: []*common.Payload{{Data: inputBytes}}, } } ``` ### Error Handling - gRPC errors → map to HTTP status: - `codes.NotFound` → 404 - `codes.InvalidArgument` → 400 - `codes.Unavailable` → 503 - others → 500 ## Questions / Blockers None currently. gRPC wiring is straightforward pattern-matching.