docs
0
# Waiters and Polling
1
2
Automated polling utilities for Lambda resources that wait until functions, versions, and configurations reach desired states, providing robust handling of asynchronous operations with configurable retry policies.
3
4
## Capabilities
5
6
### AWSLambdaWaiters
7
8
Central waiter class providing pre-configured polling strategies for common Lambda resource state transitions.
9
10
```java { .api }
11
/**
12
* Provides waiter objects for polling Lambda resources until desired state
13
* Handles common asynchronous operations with automatic retry and backoff
14
*/
15
public class AWSLambdaWaiters {
16
17
/**
18
* Creates waiters instance for Lambda client
19
* @param client AWSLambda client for resource polling
20
* @return Configured waiters instance
21
*/
22
public static AWSLambdaWaiters of(AWSLambda client);
23
24
/**
25
* Waits until Lambda function exists and is accessible
26
* Polls GetFunction API until function is found or timeout reached
27
* @return Waiter configured for function existence checking
28
* Configuration: 20 attempts, 1 second delay between attempts
29
*/
30
public Waiter<GetFunctionRequest> functionExists();
31
32
/**
33
* Waits until function configuration state is Active
34
* Monitors function state transitions during updates and deployments
35
* @return Waiter configured for function active state
36
* Configuration: 60 attempts, 5 seconds delay between attempts (5 minutes total)
37
*/
38
public Waiter<GetFunctionConfigurationRequest> functionActive();
39
40
/**
41
* Waits until function update operation completes successfully
42
* Monitors LastUpdateStatus until Successful or Failed state reached
43
* @return Waiter configured for function update completion
44
* Configuration: 60 attempts, 5 seconds delay between attempts (5 minutes total)
45
*/
46
public Waiter<GetFunctionConfigurationRequest> functionUpdated();
47
48
/**
49
* Waits until published function version becomes active and ready for invocation
50
* Ensures version is fully deployed and available across all regions
51
* @return Waiter configured for published version active state
52
* Configuration: 312 attempts, 5 seconds delay between attempts (26 minutes total)
53
*/
54
public Waiter<GetFunctionConfigurationRequest> publishedVersionActive();
55
}
56
```
57
58
### Waiter Interface and Configuration
59
60
Core waiter functionality with customizable polling behavior and error handling.
61
62
```java { .api }
63
/**
64
* Generic waiter interface for polling AWS resources until desired state
65
* @param <T> Request type for the polling operation
66
*/
67
public interface Waiter<T> {
68
69
/**
70
* Synchronously waits until resource reaches desired state
71
* Blocks calling thread until condition met or timeout exceeded
72
* @param request Request object for polling operation
73
* @return WaiterResult containing final state and timing information
74
* @throws WaiterTimedOutException if maximum attempts exceeded
75
* @throws WaiterUnrecoverableException if unrecoverable error occurs
76
*/
77
WaiterResult<T> run(T request) throws WaiterTimedOutException, WaiterUnrecoverableException;
78
79
/**
80
* Asynchronously waits until resource reaches desired state
81
* Returns immediately with Future for non-blocking operation
82
* @param request Request object for polling operation
83
* @return Future containing WaiterResult when operation completes
84
*/
85
Future<WaiterResult<T>> runAsync(T request);
86
87
/**
88
* Asynchronously waits with custom callback handling
89
* @param request Request object for polling operation
90
* @param callback Handler for waiter events and completion
91
* @return Future for async operation control
92
*/
93
Future<WaiterResult<T>> runAsync(T request, WaiterHandler<T> callback);
94
}
95
96
/**
97
* Result of waiter operation containing state and metadata
98
* @param <T> Request type that was polled
99
*/
100
public class WaiterResult<T> {
101
102
/**
103
* Gets number of polling attempts made
104
* @return Total attempts executed before completion
105
*/
106
public int getAttemptsExecuted();
107
108
/**
109
* Gets final state of waiter operation
110
* @return WaiterState indicating success, failure, or timeout
111
*/
112
public WaiterState getWaiterState();
113
}
114
115
public enum WaiterState {
116
SUCCESS, // Desired condition met
117
RETRY, // Condition not met, will retry
118
FAILURE // Unrecoverable failure occurred
119
}
120
```
121
122
### Waiter Exception Handling
123
124
Specialized exceptions for different waiter failure scenarios.
125
126
```java { .api }
127
/**
128
* Exception thrown when waiter times out before reaching desired state
129
* Indicates maximum attempts were exceeded without success
130
*/
131
public class WaiterTimedOutException extends Exception {
132
133
/**
134
* Gets waiter result containing attempt information
135
* @return WaiterResult with details about failed attempts
136
*/
137
public WaiterResult<?> getWaiterResult();
138
}
139
140
/**
141
* Exception thrown when waiter encounters unrecoverable error
142
* Indicates polling cannot continue due to permanent failure condition
143
*/
144
public class WaiterUnrecoverableException extends Exception {
145
146
/**
147
* Creates exception with cause and waiter result
148
* @param message Error description
149
* @param cause Underlying exception that caused failure
150
* @param waiterResult Result containing attempt information
151
*/
152
public WaiterUnrecoverableException(String message, Throwable cause, WaiterResult<?> waiterResult);
153
154
/**
155
* Gets waiter result containing attempt information
156
* @return WaiterResult with details about failed attempts
157
*/
158
public WaiterResult<?> getWaiterResult();
159
}
160
```
161
162
### Waiter Event Handling
163
164
Callback interface for monitoring waiter progress and handling events.
165
166
```java { .api }
167
/**
168
* Handler interface for waiter events and state transitions
169
* Enables custom logic during polling operations
170
* @param <T> Request type being polled
171
*/
172
public interface WaiterHandler<T> {
173
174
/**
175
* Called before each polling attempt
176
* @param context Current waiter execution context
177
*/
178
void onWaiterStart(WaiterExecutionContext<T> context);
179
180
/**
181
* Called after each polling attempt
182
* @param context Current waiter execution context
183
*/
184
void onWaiterSuccess(WaiterExecutionContext<T> context);
185
186
/**
187
* Called when waiter operation fails
188
* @param context Current waiter execution context
189
* @param exception Exception that caused failure
190
*/
191
void onWaiterFailure(WaiterExecutionContext<T> context, Throwable exception);
192
}
193
194
/**
195
* Execution context providing waiter state and metadata
196
* @param <T> Request type being polled
197
*/
198
public class WaiterExecutionContext<T> {
199
200
/**
201
* Gets current polling request
202
* @return Request object for this polling attempt
203
*/
204
public T getRequest();
205
206
/**
207
* Gets current attempt number (0-based)
208
* @return Number of attempts completed so far
209
*/
210
public int getAttemptNumber();
211
212
/**
213
* Gets total time elapsed since waiter start
214
* @return Duration in milliseconds
215
*/
216
public long getElapsedTimeMillis();
217
}
218
```
219
220
## Usage Examples
221
222
### Basic Function Existence Waiting
223
224
```java
225
AWSLambda lambdaClient = AWSLambdaClientBuilder.defaultClient();
226
AWSLambdaWaiters waiters = AWSLambdaWaiters.of(lambdaClient);
227
228
// Wait for function to exist after creation
229
GetFunctionRequest request = new GetFunctionRequest()
230
.withFunctionName("newly-created-function");
231
232
try {
233
WaiterResult<GetFunctionRequest> result = waiters.functionExists().run(request);
234
System.out.println("Function exists after " + result.getAttemptsExecuted() + " attempts");
235
} catch (WaiterTimedOutException e) {
236
System.err.println("Function did not appear within expected time");
237
} catch (WaiterUnrecoverableException e) {
238
System.err.println("Unrecoverable error while waiting: " + e.getMessage());
239
}
240
```
241
242
### Waiting for Function Updates
243
244
```java
245
// Update function code
246
UpdateFunctionCodeRequest updateRequest = new UpdateFunctionCodeRequest()
247
.withFunctionName("my-function")
248
.withS3Bucket("deployment-bucket")
249
.withS3Key("my-function-v2.zip");
250
251
lambdaClient.updateFunctionCode(updateRequest);
252
253
// Wait for update to complete
254
GetFunctionConfigurationRequest configRequest = new GetFunctionConfigurationRequest()
255
.withFunctionName("my-function");
256
257
try {
258
WaiterResult<GetFunctionConfigurationRequest> result =
259
waiters.functionUpdated().run(configRequest);
260
261
System.out.println("Function update completed successfully");
262
System.out.println("Attempts: " + result.getAttemptsExecuted());
263
264
} catch (WaiterTimedOutException e) {
265
System.err.println("Function update timed out after " +
266
e.getWaiterResult().getAttemptsExecuted() + " attempts");
267
} catch (WaiterUnrecoverableException e) {
268
System.err.println("Function update failed: " + e.getMessage());
269
}
270
```
271
272
### Asynchronous Waiting with Callbacks
273
274
```java
275
// Implement custom waiter handler
276
WaiterHandler<GetFunctionConfigurationRequest> handler = new WaiterHandler<GetFunctionConfigurationRequest>() {
277
278
@Override
279
public void onWaiterStart(WaiterExecutionContext<GetFunctionConfigurationRequest> context) {
280
System.out.println("Starting wait attempt " + (context.getAttemptNumber() + 1));
281
}
282
283
@Override
284
public void onWaiterSuccess(WaiterExecutionContext<GetFunctionConfigurationRequest> context) {
285
System.out.println("Function is now active after " +
286
context.getElapsedTimeMillis() + "ms");
287
}
288
289
@Override
290
public void onWaiterFailure(WaiterExecutionContext<GetFunctionConfigurationRequest> context,
291
Throwable exception) {
292
System.err.println("Wait failed at attempt " + context.getAttemptNumber() +
293
": " + exception.getMessage());
294
}
295
};
296
297
// Wait asynchronously for function to become active
298
GetFunctionConfigurationRequest configRequest = new GetFunctionConfigurationRequest()
299
.withFunctionName("deployment-target");
300
301
Future<WaiterResult<GetFunctionConfigurationRequest>> future =
302
waiters.functionActive().runAsync(configRequest, handler);
303
304
// Continue with other work while waiting
305
performOtherOperations();
306
307
// Get result when needed
308
try {
309
WaiterResult<GetFunctionConfigurationRequest> result = future.get(10, TimeUnit.MINUTES);
310
System.out.println("Function is active and ready for use");
311
} catch (TimeoutException e) {
312
System.err.println("Async wait timed out");
313
future.cancel(true);
314
}
315
```
316
317
### Version Publication Workflow
318
319
```java
320
public class VersionDeploymentManager {
321
private final AWSLambda lambdaClient;
322
private final AWSLambdaWaiters waiters;
323
324
public VersionDeploymentManager(AWSLambda lambdaClient) {
325
this.lambdaClient = lambdaClient;
326
this.waiters = AWSLambdaWaiters.of(lambdaClient);
327
}
328
329
/**
330
* Deploy new version and wait for it to be fully active
331
*/
332
public String deployNewVersion(String functionName, String description) {
333
try {
334
// Publish new version
335
PublishVersionRequest publishRequest = new PublishVersionRequest()
336
.withFunctionName(functionName)
337
.withDescription(description);
338
339
PublishVersionResult publishResult = lambdaClient.publishVersion(publishRequest);
340
String newVersion = publishResult.getVersion();
341
342
System.out.println("Published version " + newVersion + ", waiting for activation...");
343
344
// Wait for version to become active
345
GetFunctionConfigurationRequest configRequest = new GetFunctionConfigurationRequest()
346
.withFunctionName(functionName)
347
.withQualifier(newVersion);
348
349
WaiterResult<GetFunctionConfigurationRequest> waiterResult =
350
waiters.publishedVersionActive().run(configRequest);
351
352
System.out.println("Version " + newVersion + " is now active after " +
353
waiterResult.getAttemptsExecuted() + " polling attempts");
354
355
return newVersion;
356
357
} catch (WaiterTimedOutException e) {
358
throw new RuntimeException("Version activation timed out after " +
359
e.getWaiterResult().getAttemptsExecuted() + " attempts");
360
} catch (WaiterUnrecoverableException e) {
361
throw new RuntimeException("Version activation failed permanently", e);
362
}
363
}
364
365
/**
366
* Deploy with alias update and traffic shifting
367
*/
368
public void deployToAlias(String functionName, String aliasName, String description) {
369
try {
370
// Deploy new version
371
String newVersion = deployNewVersion(functionName, description);
372
373
// Update alias to point to new version
374
UpdateAliasRequest aliasRequest = new UpdateAliasRequest()
375
.withFunctionName(functionName)
376
.withName(aliasName)
377
.withFunctionVersion(newVersion);
378
379
lambdaClient.updateAlias(aliasRequest);
380
System.out.println("Alias " + aliasName + " updated to version " + newVersion);
381
382
} catch (Exception e) {
383
System.err.println("Deployment failed: " + e.getMessage());
384
throw e;
385
}
386
}
387
}
388
```
389
390
### Batch Operations with Waiters
391
392
```java
393
public class BatchFunctionManager {
394
private final AWSLambda lambdaClient;
395
private final AWSLambdaWaiters waiters;
396
private final ExecutorService executorService;
397
398
public BatchFunctionManager(AWSLambda lambdaClient) {
399
this.lambdaClient = lambdaClient;
400
this.waiters = AWSLambdaWaiters.of(lambdaClient);
401
this.executorService = Executors.newFixedThreadPool(10);
402
}
403
404
/**
405
* Update multiple functions concurrently and wait for all to complete
406
*/
407
public void updateFunctionsConcurrently(List<String> functionNames,
408
Map<String, FunctionCode> codeUpdates) {
409
List<Future<String>> futures = new ArrayList<>();
410
411
// Start all updates concurrently
412
for (String functionName : functionNames) {
413
Future<String> future = executorService.submit(() -> {
414
return updateSingleFunction(functionName, codeUpdates.get(functionName));
415
});
416
futures.add(future);
417
}
418
419
// Wait for all updates to complete
420
List<String> results = new ArrayList<>();
421
for (Future<String> future : futures) {
422
try {
423
String result = future.get(10, TimeUnit.MINUTES);
424
results.add(result);
425
} catch (Exception e) {
426
System.err.println("Function update failed: " + e.getMessage());
427
}
428
}
429
430
System.out.println("Updated " + results.size() + " functions successfully");
431
}
432
433
private String updateSingleFunction(String functionName, FunctionCode code) {
434
try {
435
// Update function code
436
UpdateFunctionCodeRequest updateRequest = new UpdateFunctionCodeRequest()
437
.withFunctionName(functionName)
438
.withS3Bucket(code.getS3Bucket())
439
.withS3Key(code.getS3Key());
440
441
lambdaClient.updateFunctionCode(updateRequest);
442
443
// Wait for update completion
444
GetFunctionConfigurationRequest configRequest = new GetFunctionConfigurationRequest()
445
.withFunctionName(functionName);
446
447
WaiterResult<GetFunctionConfigurationRequest> result =
448
waiters.functionUpdated().run(configRequest);
449
450
return "Function " + functionName + " updated in " +
451
result.getAttemptsExecuted() + " attempts";
452
453
} catch (Exception e) {
454
throw new RuntimeException("Failed to update function " + functionName, e);
455
}
456
}
457
}
458
```
459
460
### Custom Waiter Implementation
461
462
```java
463
public class CustomLambdaWaiter {
464
private final AWSLambda lambdaClient;
465
466
public CustomLambdaWaiter(AWSLambda lambdaClient) {
467
this.lambdaClient = lambdaClient;
468
}
469
470
/**
471
* Wait for provisioned concurrency to be ready with custom polling
472
*/
473
public void waitForProvisionedConcurrency(String functionName, String qualifier,
474
int maxAttempts, long delayMs) {
475
476
GetProvisionedConcurrencyConfigRequest request = new GetProvisionedConcurrencyConfigRequest()
477
.withFunctionName(functionName)
478
.withQualifier(qualifier);
479
480
int attempt = 0;
481
while (attempt < maxAttempts) {
482
try {
483
GetProvisionedConcurrencyConfigResult result =
484
lambdaClient.getProvisionedConcurrencyConfig(request);
485
486
ProvisionedConcurrencyStatus status = result.getStatus();
487
System.out.println("Attempt " + (attempt + 1) + ": Status is " + status);
488
489
if (ProvisionedConcurrencyStatus.READY.equals(status)) {
490
System.out.println("Provisioned concurrency is ready!");
491
return;
492
} else if (ProvisionedConcurrencyStatus.FAILED.equals(status)) {
493
throw new RuntimeException("Provisioned concurrency failed: " +
494
result.getStatusReason());
495
}
496
497
// Wait before next attempt
498
Thread.sleep(delayMs);
499
attempt++;
500
501
} catch (InterruptedException e) {
502
Thread.currentThread().interrupt();
503
throw new RuntimeException("Interrupted while waiting", e);
504
}
505
}
506
507
throw new RuntimeException("Provisioned concurrency did not become ready after " +
508
maxAttempts + " attempts");
509
}
510
511
/**
512
* Wait for multiple functions to be active with progress reporting
513
*/
514
public void waitForMultipleFunctions(List<String> functionNames) {
515
Set<String> pendingFunctions = new HashSet<>(functionNames);
516
int totalAttempts = 0;
517
final int maxAttempts = 60;
518
519
while (!pendingFunctions.isEmpty() && totalAttempts < maxAttempts) {
520
Iterator<String> iterator = pendingFunctions.iterator();
521
522
while (iterator.hasNext()) {
523
String functionName = iterator.next();
524
525
try {
526
GetFunctionConfigurationRequest request = new GetFunctionConfigurationRequest()
527
.withFunctionName(functionName);
528
529
GetFunctionConfigurationResult result =
530
lambdaClient.getFunctionConfiguration(request);
531
532
if (State.Active.equals(result.getState()) &&
533
LastUpdateStatus.Successful.equals(result.getLastUpdateStatus())) {
534
535
System.out.println("Function " + functionName + " is now active");
536
iterator.remove();
537
}
538
539
} catch (ResourceNotFoundException e) {
540
// Function doesn't exist yet, keep waiting
541
}
542
}
543
544
if (!pendingFunctions.isEmpty()) {
545
System.out.println("Still waiting for " + pendingFunctions.size() +
546
" functions: " + pendingFunctions);
547
548
try {
549
Thread.sleep(5000);
550
} catch (InterruptedException e) {
551
Thread.currentThread().interrupt();
552
throw new RuntimeException("Interrupted while waiting", e);
553
}
554
}
555
556
totalAttempts++;
557
}
558
559
if (!pendingFunctions.isEmpty()) {
560
throw new RuntimeException("Functions not ready after maximum attempts: " +
561
pendingFunctions);
562
}
563
564
System.out.println("All functions are now active and ready");
565
}
566
}
567
```
568
569
## Exception Handling
570
571
Common exceptions when using waiters:
572
573
- **WaiterTimedOutException**: Maximum polling attempts exceeded without reaching desired state
574
- **WaiterUnrecoverableException**: Permanent failure condition prevents continued polling
575
- **ResourceNotFoundException**: Target resource does not exist and cannot be polled
576
- **InterruptedException**: Waiter thread was interrupted during polling delay
577
- **ExecutionException**: Async waiter operation failed with underlying exception
578
579
## Best Practices
580
581
### Waiter Configuration
582
- Choose appropriate timeout values based on expected operation duration
583
- Use shorter delays for fast operations, longer delays for deployment operations
584
- Consider resource limits and API throttling when setting polling frequency
585
- Implement exponential backoff for operations prone to transient failures
586
587
### Error Handling
588
- Distinguish between temporary failures (retry) and permanent failures (abort)
589
- Log waiter progress for debugging and monitoring purposes
590
- Implement fallback strategies for waiter timeouts
591
- Use circuit breaker patterns to prevent cascading failures
592
593
### Performance Optimization
594
- Use asynchronous waiters for non-blocking operations
595
- Batch multiple waiter operations when possible
596
- Monitor API usage to avoid throttling limits
597
- Cache waiter instances to reduce initialization overhead
598
599
### Monitoring and Observability
600
- Track waiter success rates and average completion times
601
- Set up alerts for frequent waiter timeouts or failures
602
- Log waiter events for troubleshooting deployment issues
603
- Use structured logging for correlation with other operations