# Temporal REST API Gateway - Design Summary ## 🎯 Design Philosophy **Goal**: Expose all Temporal operations through a **single unified `/workflow` REST endpoint** instead of requiring direct connections to multiple Temporal ports (7233, 7234, 6933). **Key Principle**: Parameter-driven actions instead of path-based routing. ``` OLD (Direct Temporal): - gRPC call to localhost:7233 - Metrics call to localhost:6933:metrics - Multiple connection types NEW (REST Gateway): - Single HTTP POST to https://api.riotpiao.com/workflow - Specify action and namespace in request body - All operations use same endpoint ``` --- ## 📋 Unified Request Format ### Standard Structure Every request follows this format: ```json { "action": "OPERATION_NAME", "namespace": "default", "payload": { "operation_specific_fields": "values" } } ``` ### Standard Response (Success) ```json { "success": true, "action": "OPERATION_NAME", "namespace": "default", "data": {...}, "timestamp": "2024-01-15T10:30:00Z" } ``` ### Standard Response (Error) ```json { "success": false, "action": "OPERATION_NAME", "error": "ERROR_CODE", "message": "Human readable message", "timestamp": "2024-01-15T10:30:00Z" } ``` **Benefits**: - ✅ Predictable structure - ✅ Easy for clients to parse - ✅ Consistent error handling - ✅ Enables middleware logging/monitoring - ✅ Language-agnostic --- ## 📊 Operations Taxonomy ### 24 Total Operations **Workflow Operations** (10): 1. START_WORKFLOW 2. DESCRIBE_WORKFLOW 3. LIST_WORKFLOWS 4. GET_WORKFLOW_HISTORY 5. TERMINATE_WORKFLOW 6. CANCEL_WORKFLOW 7. SIGNAL_WORKFLOW 8. QUERY_WORKFLOW 9. RESET_WORKFLOW 10. UPDATE_WORKFLOW **Activity Operations** (3): 11. HEARTBEAT_ACTIVITY 12. COMPLETE_ACTIVITY 13. FAIL_ACTIVITY **Namespace Operations** (5): 14. LIST_NAMESPACES 15. DESCRIBE_NAMESPACE 16. CREATE_NAMESPACE 17. UPDATE_NAMESPACE 18. DELETE_NAMESPACE **Search Attributes** (2): 19. LIST_SEARCH_ATTRIBUTES 20. ADD_SEARCH_ATTRIBUTES **Task Queue Monitoring** (1): 21. LIST_TASK_QUEUES ⭐ (See TaskQueue recommendation below) **Cluster Operations** (3): 22. GET_CLUSTER_INFO 23. LIST_CLUSTER_MEMBERS 24. GET_SYSTEM_INFO **Special**: - GET_METRICS (via POST or direct HTTP GET) - Health checks (separate endpoint) --- ## 🚀 Key Design Decisions ### 1. Single POST Endpoint **Decision**: Use POST `/workflow` for all CRUD operations **Rationale**: - REST is primarily GET (read), but Temporal has mixed operations - POST allows request body with rich parameters - Allows for future query DSL if needed - Cleaner than /workflow/{operation} pattern **Trade-off**: Not 100% RESTful (REST purists prefer /resource/id/action), but more practical --- ### 2. Action-Based Routing **Decision**: Use `"action"` field instead of path routing ```json // ✅ GOOD (chosen) POST /workflow { "action": "START_WORKFLOW", "payload": {...} } // ❌ NOT CHOSEN POST /workflow/start POST /workflows/executions/start ``` **Rationale**: - Single endpoint for all operations - Easier middleware/auth integration - Cleaner error handling - Future-proof for new operations --- ### 3. Namespace as First-Class Field **Decision**: Include `namespace` in every request (not in URL path) ```json // ✅ GOOD (chosen) { "action": "...", "namespace": "production", "payload": {...} } // ❌ NOT CHOSEN POST /workflow/production/start ``` **Rationale**: - Namespace is runtime parameter, not structural - Allows easy namespace switching in same request - Consistent with Temporal SDK patterns - Simplifies multi-tenant scenarios --- ### 4. Pagination via Token **Decision**: Use opaque `next_page_token` for pagination (not offset) ```json { "action": "LIST_WORKFLOWS", "payload": { "page_size": 50, "next_page_token": "opaque_token_from_previous" } } ``` **Rationale**: - Matches Temporal's native pagination - Handles distributed state better - Prevents offset consistency issues - More efficient for large datasets --- ### 5. Filters as Map, Not DSL **Decision**: Use structured filters object (not string filter syntax) ```json // ✅ GOOD (chosen) { "filters": { "status": "RUNNING", "workflow_type": "OrderProcessing", "start_time_from": "2024-01-10T00:00:00Z" } } // ❌ NOT CHOSEN { "filter": "ExecutionStatus = RUNNING AND WorkflowType = 'OrderProcessing'" } ``` **Rationale**: - Type safety (can validate fields) - Better IDE support - Easier to build dynamically - Prevents filter injection attacks --- ## 💡 TaskQueue Management Recommendation ### The Problem TaskQueues in Temporal are: - Created automatically when workers connect - Managed by the cluster - Hard to monitor without direct cluster access - Critical for worker load distribution ### The Options #### Option A: Full CRUD (NOT RECOMMENDED) ```json { "action": "CREATE_TASK_QUEUE", "payload": {"name": "custom_queue"} } ``` **Problems**: Can't actually create; only workers can; confuses users #### Option B: Ignore Completely (NOT RECOMMENDED) **Problems**: No visibility into queue health; silent failures if queues break #### **Option C: Read-Only Monitor (RECOMMENDED) ⭐** ```json { "action": "LIST_TASK_QUEUES", "namespace": "default", "payload": { "queue_type": "WORKFLOW" } } ``` **Response**: ```json { "data": { "queues": [ { "name": "main_queue", "type": "WORKFLOW", "reader_count": 3, "poison_pill_count": 0, "ack_level": 1050, "last_activity": "2024-01-15T10:32:00Z" } ] } } ``` --- ### TaskQueue Recommendation Analysis | Aspect | Option A (CRUD) | Option B (Ignore) | **Option C (Monitor)** | |--------|---|---|---| | **Complexity** | High | Low | Medium | | **User Confusion** | ❌ High | ✅ None | ✅ Low | | **Operational Visibility** | ✅ Full | ❌ None | ✅ Good | | **Can Debug Issues** | ✅ Yes | ❌ No | ✅ Yes | | **Monitoring/Alerting** | ✅ Can do | ❌ No | ✅ Can do | | **Consistent with Temporal** | ❌ No | ✅ Yes | ✅ Yes | | **Works with Worker Lifecycle** | ❌ Conflicts | ✅ Yes | ✅ Yes | **WINNER**: **Option C - Read-Only Monitor** ⭐ --- ## 🎯 Pros & Cons of Option C (TaskQueue Read-Only Monitor) ### Pros ✅ 1. **Operational Visibility** - Know which queues are active - Monitor reader count (detect stuck workers) - Track poison pills (detect failing tasks) 2. **Debugging** - Identify if queue is the problem - Verify workers are connected - Check ack_level for progress 3. **Monitoring & Alerting** - Alert if reader_count drops to 0 - Alert if poison_pill_count increases - Dashboard metrics 4. **No Conflicts** - Doesn't interfere with worker lifecycle - Matches Temporal semantics - Read-only (safe) 5. **API Completeness** - Exposes all Temporal concepts - Users can see everything through REST API - No "magic" hidden state 6. **Production Support** - Support teams can diagnose issues - Self-service monitoring - Reduces support tickets ### Cons ❌ 1. **Limited Utility** - Can't create/delete queues (workers do this) - Can't configure queue behavior - Read-only doesn't feel "complete" 2. **Not Needed for Normal Ops** - Most users just start workflows - Workers auto-create queues - Queue monitoring rarely needed 3. **Adds Complexity** - One more operation to document - Need to explain read-only nature - More API surface area 4. **Requires Metrics Knowledge** - Users need to understand what fields mean - poison_pill_count, ack_level aren't intuitive --- ## 🔒 Data Flow & Security ``` Client Request ↓ API Gateway (https://api.riotpiao.com/workflow) ↓ Request Validation & Auth (Phase 3) ↓ Action Router ├→ [Workflow Operations] → Temporal gRPC :7233 ├→ [Namespace Operations] → Temporal gRPC :7233 ├→ [Search Attributes] → Temporal gRPC :7233 ├→ [Activity Operations] → Temporal gRPC :7233 ├→ [Cluster Operations] → Temporal gRPC :7233 ├→ [Metrics] → Prometheus :6933 └→ [Health Check] → Internal check ↓ Response Formatting (unified JSON) ↓ Client Response ``` **Security**: All requests go through gateway auth layer (TBD Phase 3) --- ## 📈 Performance Implications ### gRPC Over HTTP/2 - Temporal's native protocol is gRPC - HTTP/2 is built for gRPC - No additional overhead vs direct gRPC - Slightly more latency: ~1-5ms extra ### Metrics Endpoint - Prometheus scrapes from `:6933` - Gateway acts as reverse proxy - No aggregation needed - Direct forwarding: minimal latency ### Connection Pooling - Maintain persistent gRPC connections - Reuse connections for multiple requests - Connection pooling inside gateway --- ## 🗂️ Implementation Roadmap ### Phase 1 (This Implementation) - ✅ Unified REST API design - ✅ All 24 operations mapped - ✅ gRPC integration - ✅ Metrics endpoint - ✅ Comprehensive documentation ### Phase 2 (Follow-up) - Error handling & retries - Request validation - Response transformation - Test coverage ### Phase 3 - Bearer token authentication - Namespace-based authorization - Audit logging ### Phase 4 - Rate limiting - Metrics aggregation - Advanced caching --- ## 📚 Documentation Structure | Document | Purpose | Length | |----------|---------|--------| | **TEMPORAL_USAGE.md** | Complete API reference with all 24 operations | ~22KB | | **TEMPORAL_API_DESIGN_SUMMARY.md** | This document - design decisions & recommendations | ~5KB | | **TEMPORAL_IMPLEMENTATION.md** | Implementation guide (TBD) | TBD | --- ## ✅ Design Review Checklist - ✅ Single unified endpoint (`/workflow`) - ✅ Standard request/response format - ✅ All 24 Temporal operations covered - ✅ Action-based routing (not path-based) - ✅ Namespace as request parameter - ✅ Pagination via token - ✅ Structured filters (not DSL) - ✅ TaskQueue monitoring (read-only) - ✅ Error handling standardized - ✅ Metrics endpoint exposed - ✅ Health check endpoint - ✅ Extensible for future operations - ✅ No direct path dependencies - ✅ No port exposure needed --- ## 🎓 Usage Example ### Before (Direct Temporal) ```python # Multiple imports needed import grpc from temporal.api.workflowservice import v1 as wf_service from temporal.api.operatorservice import v1 as op_service # Multiple clients needed workflow_channel = grpc.aio.secure_channel( "localhost:7233", grpc.ssl_channel_credentials() ) wf_client = wf_service.WorkflowServiceStub(workflow_channel) metrics_response = requests.get("http://localhost:6933/metrics") # Different API styles await wf_client.StartWorkflowExecution(request) ``` ### After (REST Gateway) ```python import requests # Single endpoint, single client api = "https://api.riotpiao.com/workflow" # Start workflow response = requests.post(api, json={ "action": "START_WORKFLOW", "namespace": "default", "payload": { "workflow_id": "wf_001", "workflow_type": "ProcessOrder", "task_queue": "orders", "input": {"order_id": "123"} } }) # Get metrics metrics = requests.get("https://api.riotpiao.com/workflow/metrics") # All through same client! ``` --- ## 🚀 Next Steps 1. **Review** this design document 2. **Approve** TaskQueue recommendation (Option C) 3. **Implement** gateway integration with Temporal Go SDK 4. **Test** all 24 operations 5. **Deploy** to development environment 6. **Document** with examples in each language --- ## 📞 Questions? - TaskQueue recommendation: See analysis above - API design: See TEMPORAL_USAGE.md - Implementation: See TEMPORAL_IMPLEMENTATION.md (TBD) **Status**: Design Phase Complete ✅ **Ready for Implementation**: Yes ✅