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)
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user