0
# Long-Running Operations
1
2
Support for asynchronous operations that may take significant time to complete. Provides standard patterns for operation management, polling, result retrieval, and cancellation across Google services.
3
4
## Capabilities
5
6
### Operation Representation
7
8
Core operation message representing asynchronous operations with metadata and results.
9
10
```python { .api }
11
from google.longrunning.operations_proto_pb2 import Operation, OperationInfo
12
13
class Operation(message.Message):
14
"""Long-running operation representation."""
15
name: str # Operation resource name (unique identifier)
16
metadata: Any # Operation-specific metadata
17
done: bool # True when operation is complete
18
# Union field 'result' (one of):
19
error: Status # Error result if operation failed
20
response: Any # Success result if operation completed
21
22
class OperationInfo(message.Message):
23
"""Operation type information."""
24
response_type: str # Expected response message type
25
metadata_type: str # Expected metadata message type
26
```
27
28
### Operation Management Requests
29
30
Standard request messages for managing long-running operations.
31
32
```python { .api }
33
from google.longrunning.operations_proto_pb2 import (
34
GetOperationRequest, ListOperationsRequest, ListOperationsResponse,
35
CancelOperationRequest, DeleteOperationRequest, WaitOperationRequest
36
)
37
38
class GetOperationRequest(message.Message):
39
"""Request to get an operation by name."""
40
name: str # Operation name to retrieve
41
42
class ListOperationsRequest(message.Message):
43
"""Request to list operations."""
44
name: str # Parent resource name for filtering
45
filter: str # Filter expression
46
page_size: int # Maximum number of operations to return
47
page_token: str # Page token for pagination
48
49
class ListOperationsResponse(message.Message):
50
"""Response containing list of operations."""
51
operations: list[Operation] # List of operations
52
next_page_token: str # Token for next page (if any)
53
54
class CancelOperationRequest(message.Message):
55
"""Request to cancel an operation."""
56
name: str # Operation name to cancel
57
58
class DeleteOperationRequest(message.Message):
59
"""Request to delete an operation."""
60
name: str # Operation name to delete
61
62
class WaitOperationRequest(message.Message):
63
"""Request to wait for operation completion."""
64
name: str # Operation name to wait for
65
timeout: Duration # Maximum time to wait
66
```
67
68
## Usage Examples
69
70
### Checking Operation Status
71
72
```python
73
from google.longrunning.operations_proto_pb2 import Operation, GetOperationRequest
74
from google.rpc.status_pb2 import Status
75
76
def check_operation_status(operation: Operation):
77
"""Check and handle operation status."""
78
if operation.done:
79
if operation.HasField('error'):
80
# Operation failed
81
print(f"Operation failed: {operation.error.message}")
82
return False
83
elif operation.HasField('response'):
84
# Operation completed successfully
85
print("Operation completed successfully")
86
return True
87
else:
88
# Operation still in progress
89
print(f"Operation {operation.name} is still running...")
90
return False
91
92
# Example usage
93
operation = Operation()
94
operation.name = "projects/my-project/operations/12345"
95
operation.done = False
96
97
# Check status
98
is_complete = check_operation_status(operation)
99
```
100
101
### Polling for Operation Completion
102
103
```python
104
import time
105
from google.longrunning.operations_proto_pb2 import GetOperationRequest
106
from google.protobuf.duration_pb2 import Duration
107
108
def poll_operation(operation_name: str, client, max_wait_seconds: int = 300):
109
"""Poll operation until completion or timeout."""
110
start_time = time.time()
111
poll_interval = 1 # Start with 1 second
112
max_poll_interval = 60 # Cap at 60 seconds
113
114
while time.time() - start_time < max_wait_seconds:
115
# Get current operation status
116
request = GetOperationRequest()
117
request.name = operation_name
118
119
operation = client.get_operation(request)
120
121
if operation.done:
122
if operation.HasField('error'):
123
raise Exception(f"Operation failed: {operation.error.message}")
124
return operation.response
125
126
# Wait before next poll with exponential backoff
127
time.sleep(poll_interval)
128
poll_interval = min(poll_interval * 1.5, max_poll_interval)
129
130
raise TimeoutError(f"Operation {operation_name} did not complete within {max_wait_seconds} seconds")
131
```
132
133
### Creating Operation Metadata
134
135
```python
136
from google.longrunning.operations_proto_pb2 import Operation
137
from google.protobuf.any_pb2 import Any
138
from google.protobuf.timestamp_pb2 import Timestamp
139
140
# Custom metadata message (example)
141
class CreateInstanceMetadata:
142
"""Example metadata for instance creation."""
143
def __init__(self):
144
self.start_time = Timestamp()
145
self.start_time.GetCurrentTime()
146
self.progress_percent = 0
147
self.status_message = "Starting instance creation"
148
149
def create_operation_with_metadata(operation_name: str, metadata) -> Operation:
150
"""Create operation with custom metadata."""
151
operation = Operation()
152
operation.name = operation_name
153
operation.done = False
154
155
# Pack metadata into Any field
156
metadata_any = Any()
157
metadata_any.Pack(metadata)
158
operation.metadata.CopyFrom(metadata_any)
159
160
return operation
161
```
162
163
### Operation Result Handling
164
165
```python
166
from google.protobuf.any_pb2 import Any
167
168
def extract_operation_result(operation: Operation, expected_type):
169
"""Extract strongly-typed result from operation."""
170
if not operation.done:
171
raise ValueError("Operation is not yet complete")
172
173
if operation.HasField('error'):
174
raise Exception(f"Operation failed: {operation.error.message}")
175
176
if not operation.HasField('response'):
177
raise ValueError("Operation completed but has no response")
178
179
# Unpack the response to expected type
180
result = expected_type()
181
operation.response.Unpack(result)
182
return result
183
184
# Example usage with custom response type
185
class CreateInstanceResponse:
186
"""Example response for instance creation."""
187
def __init__(self):
188
self.instance_id = ""
189
self.instance_name = ""
190
self.status = "RUNNING"
191
192
# Usage
193
# operation = get_completed_operation()
194
# result = extract_operation_result(operation, CreateInstanceResponse)
195
# print(f"Created instance: {result.instance_id}")
196
```
197
198
### Operation Cancellation
199
200
```python
201
from google.longrunning.operations_proto_pb2 import CancelOperationRequest
202
203
def cancel_operation(operation_name: str, client):
204
"""Cancel a long-running operation."""
205
request = CancelOperationRequest()
206
request.name = operation_name
207
208
try:
209
client.cancel_operation(request)
210
print(f"Cancellation requested for operation: {operation_name}")
211
212
# Check if cancellation was successful
213
get_request = GetOperationRequest()
214
get_request.name = operation_name
215
operation = client.get_operation(get_request)
216
217
if operation.done and operation.HasField('error'):
218
if operation.error.code == 1: # CANCELLED
219
print("Operation was successfully cancelled")
220
else:
221
print(f"Operation failed with error: {operation.error.message}")
222
else:
223
print("Cancellation may still be in progress")
224
225
except Exception as e:
226
print(f"Failed to cancel operation: {e}")
227
```
228
229
### Listing Operations with Filtering
230
231
```python
232
from google.longrunning.operations_proto_pb2 import ListOperationsRequest
233
234
def list_operations(parent: str, client, filter_expr: str = "", page_size: int = 50):
235
"""List operations with filtering and pagination."""
236
request = ListOperationsRequest()
237
request.name = parent
238
request.filter = filter_expr
239
request.page_size = page_size
240
241
all_operations = []
242
243
while True:
244
response = client.list_operations(request)
245
all_operations.extend(response.operations)
246
247
# Check if there are more pages
248
if not response.next_page_token:
249
break
250
251
# Set up next page request
252
request.page_token = response.next_page_token
253
254
return all_operations
255
256
# Example usage
257
parent = "projects/my-project"
258
filter_expr = "done=false" # Only incomplete operations
259
operations = list_operations(parent, client, filter_expr)
260
261
for op in operations:
262
print(f"Operation: {op.name}, Done: {op.done}")
263
```
264
265
### Waiting for Operation with Timeout
266
267
```python
268
from google.longrunning.operations_proto_pb2 import WaitOperationRequest
269
from google.protobuf.duration_pb2 import Duration
270
271
def wait_for_operation(operation_name: str, client, timeout_seconds: int = 300):
272
"""Wait for operation to complete with specified timeout."""
273
request = WaitOperationRequest()
274
request.name = operation_name
275
276
# Set timeout
277
request.timeout.seconds = timeout_seconds
278
279
try:
280
# This call blocks until operation completes or timeout
281
operation = client.wait_operation(request)
282
283
if operation.HasField('error'):
284
raise Exception(f"Operation failed: {operation.error.message}")
285
286
print(f"Operation {operation_name} completed successfully")
287
return operation.response
288
289
except Exception as e:
290
if "timeout" in str(e).lower():
291
print(f"Operation {operation_name} did not complete within {timeout_seconds} seconds")
292
raise
293
```
294
295
### Operation Progress Tracking
296
297
```python
298
from google.protobuf.any_pb2 import Any
299
300
def track_operation_progress(operation: Operation):
301
"""Extract and display progress information from operation metadata."""
302
if not operation.metadata:
303
print("No metadata available")
304
return
305
306
# Try to extract common progress information
307
# This would depend on the specific metadata type
308
try:
309
# Example for a hypothetical progress metadata
310
if operation.metadata.type_url.endswith("ProgressMetadata"):
311
# Unpack metadata (this is service-specific)
312
print(f"Operation {operation.name} progress tracking:")
313
print(f" Status: {'Complete' if operation.done else 'In Progress'}")
314
315
if operation.done:
316
if operation.HasField('error'):
317
print(f" Error: {operation.error.message}")
318
else:
319
print(" Result: Success")
320
else:
321
print(" Still processing...")
322
323
except Exception as e:
324
print(f"Could not extract progress information: {e}")
325
326
# Example usage in a monitoring loop
327
def monitor_operation(operation_name: str, client, check_interval: int = 10):
328
"""Monitor operation progress with periodic updates."""
329
while True:
330
request = GetOperationRequest()
331
request.name = operation_name
332
operation = client.get_operation(request)
333
334
track_operation_progress(operation)
335
336
if operation.done:
337
break
338
339
time.sleep(check_interval)
340
```