redis_cloud/tasks.rs
1//! Asynchronous task tracking and management
2//!
3//! This module provides functionality for tracking long-running operations in
4//! Redis Cloud. Many API operations are asynchronous and return a task ID that
5//! can be used to monitor progress and completion status.
6//!
7//! # Overview
8//!
9//! Redis Cloud uses tasks for operations that may take time to complete, such as:
10//! - Creating or deleting subscriptions
11//! - Database creation, updates, and deletion
12//! - Backup and restore operations
13//! - Import/export operations
14//! - Network configuration changes
15//!
16//! # Task Lifecycle
17//!
18//! 1. **Initiated**: Task is created and queued
19//! 2. **Processing**: Task is being executed
20//! 3. **Completed**: Task finished successfully
21//! 4. **Failed**: Task encountered an error
22//!
23//! # Key Features
24//!
25//! - **Task Status**: Check current status of any task
26//! - **Progress Tracking**: Monitor completion percentage for long operations
27//! - **Result Retrieval**: Get operation results once completed
28//! - **Error Information**: Access detailed error messages for failed tasks
29//! - **Task History**: Query historical task information
30//!
31//! # Example Usage
32//!
33//! ```no_run
34//! use redis_cloud::{CloudClient, TaskHandler};
35//!
36//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
37//! let client = CloudClient::builder()
38//! .api_key("your-api-key")
39//! .api_secret("your-api-secret")
40//! .build()?;
41//!
42//! let handler = TaskHandler::new(client);
43//!
44//! // Get task status
45//! let task = handler.get_task_by_id("task-123".to_string()).await?;
46//!
47//! // Check if task is complete
48//! if task.status == Some("completed".to_string()) {
49//! println!("Task completed successfully");
50//! if let Some(response) = task.response {
51//! println!("Result: {:?}", response);
52//! }
53//! }
54//! # Ok(())
55//! # }
56//! ```
57
58use crate::{CloudClient, Result};
59use serde::{Deserialize, Serialize};
60use serde_json::Value;
61use std::collections::HashMap;
62
63// ============================================================================
64// Models
65// ============================================================================
66
67/// ProcessorResponse
68///
69/// Contains the result of an asynchronous operation
70#[derive(Debug, Clone, Serialize, Deserialize)]
71#[serde(rename_all = "camelCase")]
72pub struct ProcessorResponse {
73 /// ID of the created/modified resource
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub resource_id: Option<i32>,
76
77 /// Additional resource ID (for operations creating multiple resources)
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub additional_resource_id: Option<i32>,
80
81 /// Full resource object for the created/modified resource
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub resource: Option<HashMap<String, Value>>,
84
85 /// Error message if the operation failed
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub error: Option<String>,
88
89 /// Additional information about the operation
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub additional_info: Option<String>,
92
93 /// Only for truly unknown/future API fields
94 #[serde(flatten)]
95 pub extra: Value,
96}
97
98/// TaskStateUpdate
99///
100/// Represents the state and result of an asynchronous task
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct TaskStateUpdate {
104 /// Unique task identifier
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub task_id: Option<String>,
107
108 /// Type of command being executed (e.g., "CREATE_DATABASE", "DELETE_SUBSCRIPTION")
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub command_type: Option<String>,
111
112 /// Current task status (e.g., "processing", "completed", "failed")
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub status: Option<String>,
115
116 /// Human-readable description of the task
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub description: Option<String>,
119
120 /// Timestamp of last task update
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub timestamp: Option<String>,
123
124 /// Task completion percentage (0-100)
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub progress: Option<f64>,
127
128 /// Result data once task is completed
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub response: Option<ProcessorResponse>,
131
132 /// HATEOAS links for API navigation
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub links: Option<Vec<HashMap<String, Value>>>,
135
136 /// Only for truly unknown/future API fields
137 #[serde(flatten)]
138 pub extra: Value,
139}
140
141// ============================================================================
142// Handler
143// ============================================================================
144
145/// Handler for asynchronous task operations
146///
147/// Tracks and manages long-running operations, providing status updates,
148/// progress monitoring, and result retrieval for asynchronous API calls.
149pub struct TasksHandler {
150 client: CloudClient,
151}
152
153impl TasksHandler {
154 /// Create a new handler
155 pub fn new(client: CloudClient) -> Self {
156 Self { client }
157 }
158
159 /// Get tasks
160 /// Gets a list of all currently running tasks for this account.
161 ///
162 /// GET /tasks
163 pub async fn get_all_tasks(&self) -> Result<()> {
164 self.client.get("/tasks").await
165 }
166
167 /// Get a single task
168 /// Gets details and status of a single task by the Task ID.
169 ///
170 /// GET /tasks/{taskId}
171 pub async fn get_task_by_id(&self, task_id: String) -> Result<TaskStateUpdate> {
172 self.client.get(&format!("/tasks/{}", task_id)).await
173 }
174}