or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-infrastructure.mdapps-cards.mdcloud-platform.mdcommon-types.mdindex.mdlongrunning-operations.mdrpc-status.md

longrunning-operations.mddocs/

0

# Long-Running Operations

1

2

Support for asynchronous operations that don't complete immediately, providing status tracking, cancellation, and result retrieval. This is essential for operations that may take minutes or hours to complete.

3

4

## Core Operation Types

5

6

### Operation

7

8

Represents a long-running operation with status tracking and result handling.

9

10

```java { .api }

11

class Operation {

12

String getName(); // Unique operation identifier

13

Any getMetadata(); // Operation-specific metadata

14

boolean getDone(); // True if operation is complete

15

Status getError(); // Error status if operation failed

16

Any getResponse(); // Operation result if successful

17

18

static Operation.Builder newBuilder();

19

Operation.Builder toBuilder();

20

static Operation parseFrom(byte[] data);

21

boolean hasError();

22

boolean hasResponse();

23

}

24

25

interface OperationOrBuilder {

26

String getName();

27

Any getMetadata();

28

boolean getDone();

29

boolean hasError();

30

Status getError();

31

boolean hasResponse();

32

Any getResponse();

33

}

34

```

35

36

### OperationInfo

37

38

Metadata about operation types and their expected response/metadata types.

39

40

```java { .api }

41

class OperationInfo {

42

String getResponseType(); // Fully qualified type name of response

43

String getMetadataType(); // Fully qualified type name of metadata

44

45

static OperationInfo.Builder newBuilder();

46

}

47

```

48

49

## Request/Response Types

50

51

### GetOperationRequest

52

53

Request to retrieve the current status of an operation.

54

55

```java { .api }

56

class GetOperationRequest {

57

String getName(); // Operation name to retrieve

58

59

static GetOperationRequest.Builder newBuilder();

60

}

61

```

62

63

### ListOperationsRequest

64

65

Request to list operations matching specified criteria.

66

67

```java { .api }

68

class ListOperationsRequest {

69

String getName(); // Collection name (e.g., "operations")

70

String getFilter(); // Optional filter expression

71

int getPageSize(); // Maximum operations to return

72

String getPageToken(); // Token for pagination

73

74

static ListOperationsRequest.Builder newBuilder();

75

}

76

```

77

78

### ListOperationsResponse

79

80

Response containing a list of operations and pagination information.

81

82

```java { .api }

83

class ListOperationsResponse {

84

repeated Operation getOperationsList();

85

String getNextPageToken();

86

87

static ListOperationsResponse.Builder newBuilder();

88

int getOperationsCount();

89

Operation getOperations(int index);

90

}

91

```

92

93

### CancelOperationRequest

94

95

Request to cancel a running operation.

96

97

```java { .api }

98

class CancelOperationRequest {

99

String getName(); // Operation name to cancel

100

101

static CancelOperationRequest.Builder newBuilder();

102

}

103

```

104

105

### DeleteOperationRequest

106

107

Request to delete an operation record.

108

109

```java { .api }

110

class DeleteOperationRequest {

111

String getName(); // Operation name to delete

112

113

static DeleteOperationRequest.Builder newBuilder();

114

}

115

```

116

117

### WaitOperationRequest

118

119

Request to wait for an operation to complete.

120

121

```java { .api }

122

class WaitOperationRequest {

123

String getName();

124

Duration getTimeout(); // Maximum time to wait

125

126

static WaitOperationRequest.Builder newBuilder();

127

}

128

```

129

130

## Usage Examples

131

132

### Creating and Monitoring Operations

133

134

```java

135

import com.google.longrunning.Operation;

136

import com.google.longrunning.GetOperationRequest;

137

import com.google.protobuf.Any;

138

import com.google.rpc.Status;

139

140

// Create a new operation

141

Operation operation = Operation.newBuilder()

142

.setName("operations/my-operation-123")

143

.setDone(false)

144

.build();

145

146

// Check operation status

147

public void checkOperationStatus(String operationName) {

148

GetOperationRequest request = GetOperationRequest.newBuilder()

149

.setName(operationName)

150

.build();

151

152

// This would typically be sent to the service

153

Operation operation = operationsClient.getOperation(request);

154

155

if (operation.getDone()) {

156

if (operation.hasError()) {

157

Status error = operation.getError();

158

System.err.println("Operation failed: " + error.getMessage());

159

} else if (operation.hasResponse()) {

160

Any response = operation.getResponse();

161

System.out.println("Operation completed successfully");

162

// Process response based on expected type

163

}

164

} else {

165

System.out.println("Operation still in progress: " + operation.getName());

166

}

167

}

168

```

169

170

### Polling Pattern

171

172

```java

173

import java.util.concurrent.TimeUnit;

174

175

public class OperationPoller {

176

private static final int MAX_POLL_ATTEMPTS = 100;

177

private static final long POLL_INTERVAL_SECONDS = 5;

178

179

public Operation waitForOperation(String operationName) throws InterruptedException {

180

for (int attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {

181

GetOperationRequest request = GetOperationRequest.newBuilder()

182

.setName(operationName)

183

.build();

184

185

Operation operation = operationsClient.getOperation(request);

186

187

if (operation.getDone()) {

188

return operation;

189

}

190

191

System.out.println("Operation " + operationName + " still running, attempt " + (attempt + 1));

192

TimeUnit.SECONDS.sleep(POLL_INTERVAL_SECONDS);

193

}

194

195

throw new RuntimeException("Operation did not complete within timeout");

196

}

197

}

198

```

199

200

### Listing Operations

201

202

```java

203

import com.google.longrunning.ListOperationsRequest;

204

import com.google.longrunning.ListOperationsResponse;

205

206

public void listAllOperations(String collectionName) {

207

String pageToken = "";

208

209

do {

210

ListOperationsRequest request = ListOperationsRequest.newBuilder()

211

.setName(collectionName)

212

.setPageSize(50)

213

.setPageToken(pageToken)

214

.build();

215

216

ListOperationsResponse response = operationsClient.listOperations(request);

217

218

for (Operation operation : response.getOperationsList()) {

219

System.out.println("Operation: " + operation.getName() +

220

", Done: " + operation.getDone());

221

}

222

223

pageToken = response.getNextPageToken();

224

} while (!pageToken.isEmpty());

225

}

226

```

227

228

### Filtering Operations

229

230

```java

231

public void listPendingOperations() {

232

ListOperationsRequest request = ListOperationsRequest.newBuilder()

233

.setName("operations")

234

.setFilter("done = false") // Only show incomplete operations

235

.setPageSize(100)

236

.build();

237

238

ListOperationsResponse response = operationsClient.listOperations(request);

239

240

System.out.println("Pending operations:");

241

for (Operation operation : response.getOperationsList()) {

242

System.out.println("- " + operation.getName());

243

}

244

}

245

```

246

247

### Operation Cancellation

248

249

```java

250

import com.google.longrunning.CancelOperationRequest;

251

252

public void cancelOperation(String operationName) {

253

CancelOperationRequest request = CancelOperationRequest.newBuilder()

254

.setName(operationName)

255

.build();

256

257

try {

258

operationsClient.cancelOperation(request);

259

System.out.println("Cancellation requested for operation: " + operationName);

260

261

// Verify cancellation

262

Operation operation = operationsClient.getOperation(

263

GetOperationRequest.newBuilder().setName(operationName).build());

264

265

if (operation.getDone() && operation.hasError()) {

266

Status error = operation.getError();

267

if (error.getCode() == Code.CANCELLED.getNumber()) {

268

System.out.println("Operation successfully cancelled");

269

}

270

}

271

} catch (Exception e) {

272

System.err.println("Failed to cancel operation: " + e.getMessage());

273

}

274

}

275

```

276

277

### Working with Typed Responses

278

279

```java

280

import com.google.protobuf.InvalidProtocolBufferException;

281

282

// Example response type

283

class ProcessingResult {

284

private String resultId;

285

private int itemsProcessed;

286

// ... other fields

287

}

288

289

public ProcessingResult handleTypedOperation(Operation operation)

290

throws InvalidProtocolBufferException {

291

292

if (!operation.getDone()) {

293

throw new IllegalStateException("Operation not complete");

294

}

295

296

if (operation.hasError()) {

297

Status error = operation.getError();

298

throw new RuntimeException("Operation failed: " + error.getMessage());

299

}

300

301

if (!operation.hasResponse()) {

302

throw new IllegalStateException("Operation completed but no response");

303

}

304

305

// Unpack the Any response to the expected type

306

Any response = operation.getResponse();

307

if (response.is(ProcessingResult.class)) {

308

return response.unpack(ProcessingResult.class);

309

} else {

310

throw new IllegalArgumentException("Unexpected response type: " + response.getTypeUrl());

311

}

312

}

313

```

314

315

### Operation Metadata Handling

316

317

```java

318

// Example metadata type

319

class ProcessingMetadata {

320

private int totalItems;

321

private int processedItems;

322

private String currentPhase;

323

// ... other fields

324

}

325

326

public void displayProgress(Operation operation) throws InvalidProtocolBufferException {

327

if (operation.hasMetadata()) {

328

Any metadata = operation.getMetadata();

329

330

if (metadata.is(ProcessingMetadata.class)) {

331

ProcessingMetadata progress = metadata.unpack(ProcessingMetadata.class);

332

333

double percentComplete = (double) progress.getProcessedItems() / progress.getTotalItems() * 100;

334

335

System.out.printf("Operation %s: %.1f%% complete (%s)\n",

336

operation.getName(),

337

percentComplete,

338

progress.getCurrentPhase());

339

}

340

}

341

}

342

```

343

344

### Delete Operations

345

346

```java

347

import com.google.longrunning.DeleteOperationRequest;

348

349

public void cleanupCompletedOperations() {

350

// First, list completed operations

351

ListOperationsRequest listRequest = ListOperationsRequest.newBuilder()

352

.setName("operations")

353

.setFilter("done = true")

354

.build();

355

356

ListOperationsResponse response = operationsClient.listOperations(listRequest);

357

358

// Delete operations older than a certain threshold

359

long cutoffTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);

360

361

for (Operation operation : response.getOperationsList()) {

362

// This example assumes operation names contain timestamps

363

// In practice, you'd use metadata or other fields to determine age

364

if (shouldDeleteOperation(operation, cutoffTime)) {

365

DeleteOperationRequest deleteRequest = DeleteOperationRequest.newBuilder()

366

.setName(operation.getName())

367

.build();

368

369

try {

370

operationsClient.deleteOperation(deleteRequest);

371

System.out.println("Deleted operation: " + operation.getName());

372

} catch (Exception e) {

373

System.err.println("Failed to delete operation " + operation.getName() + ": " + e.getMessage());

374

}

375

}

376

}

377

}

378

379

private boolean shouldDeleteOperation(Operation operation, long cutoffTime) {

380

// Implementation depends on how you track operation timestamps

381

// This is just an example

382

return true; // Replace with actual logic

383

}

384

```

385

386

## Best Practices

387

388

### Operation Naming

389

390

Operations should have unique, descriptive names:

391

392

```java

393

// Good: includes service, resource type, and unique ID

394

String operationName = "operations/compute/instances/create-instance-abc123";

395

396

// Good: hierarchical naming for organization

397

String operationName = "projects/my-project/operations/backup-database-456789";

398

```

399

400

### Error Handling

401

402

Always check for errors before processing results:

403

404

```java

405

public void handleOperation(Operation operation) {

406

if (!operation.getDone()) {

407

// Operation still in progress

408

return;

409

}

410

411

if (operation.hasError()) {

412

// Handle error case

413

Status error = operation.getError();

414

handleOperationError(error);

415

return;

416

}

417

418

if (operation.hasResponse()) {

419

// Process successful result

420

processOperationResult(operation.getResponse());

421

}

422

}

423

```

424

425

### Timeout Strategies

426

427

Implement appropriate timeout strategies for different operation types:

428

429

```java

430

public class OperationConfig {

431

// Short operations: file uploads, simple transformations

432

public static final Duration SHORT_OPERATION_TIMEOUT = Duration.newBuilder()

433

.setSeconds(300) // 5 minutes

434

.build();

435

436

// Medium operations: data processing, image generation

437

public static final Duration MEDIUM_OPERATION_TIMEOUT = Duration.newBuilder()

438

.setSeconds(1800) // 30 minutes

439

.build();

440

441

// Long operations: large data imports, model training

442

public static final Duration LONG_OPERATION_TIMEOUT = Duration.newBuilder()

443

.setSeconds(7200) // 2 hours

444

.build();

445

}

446

```

447

448

### Resource Cleanup

449

450

Always clean up completed operations to avoid resource leaks:

451

452

```java

453

public void performOperationWithCleanup(String operationName) {

454

try {

455

Operation result = waitForOperation(operationName);

456

processOperationResult(result);

457

} finally {

458

// Clean up the operation record

459

try {

460

DeleteOperationRequest deleteRequest = DeleteOperationRequest.newBuilder()

461

.setName(operationName)

462

.build();

463

operationsClient.deleteOperation(deleteRequest);

464

} catch (Exception e) {

465

System.err.println("Warning: Failed to clean up operation " + operationName);

466

}

467

}

468

}

469

```