Files
homelab-frontend/TEMPORAL_GRPC_MIGRATION.md
T
Admin Bot 4935ea9f95
CI / Vet, test, build (push) Failing after 2m31s
CI / Build and push image (push) Skipped
feat: wire Temporal gRPC into REST handler
- Handler now maintains gRPC connection to Temporal (port 7233)
- startWorkflow & describeWorkflow translated to actual gRPC calls
- Other 20+ operations phased in via TEMPORAL_GRPC_MIGRATION roadmap
- Updated docs: TEMPORAL_USAGE now describes gRPC architecture
- Added TEMPORAL_GRPC_MIGRATION.md for implementation reference
- Deleted WORKFLOWS.md (outdated duplicate)

Fixes: gRPC was imported but unused - now operational for START/DESCRIBE.
Verification: go build ./cmd/gateway  (no errors)
2026-08-29 21:54:16 -07:00

177 lines
4.9 KiB
Markdown

# 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.