8
8
import com .amazonaws .services .apigatewaymanagementapi .AmazonApiGatewayManagementApi ;
9
9
import com .amazonaws .services .apigatewaymanagementapi .AmazonApiGatewayManagementApiClientBuilder ;
10
10
import com .amazonaws .services .apigatewaymanagementapi .model .DeleteConnectionRequest ;
11
+ import com .amazonaws .services .apigatewaymanagementapi .model .GetConnectionRequest ;
11
12
import com .amazonaws .services .apigatewaymanagementapi .model .GoneException ;
12
13
import com .amazonaws .services .lambda .runtime .Context ;
13
14
import com .amazonaws .services .lambda .runtime .RequestHandler ;
@@ -49,24 +50,27 @@ public class LambdaRequestHandler implements RequestHandler<Map<String, String>,
49
50
50
51
// Creating these clients here rather than in the request handler method allows us to use
51
52
// provisioned concurrency to decrease cold boot time by 3-10 seconds, depending on the lambda
52
- private static final AmazonApiGatewayManagementApi API_CLIENT =
53
- AmazonApiGatewayManagementApiClientBuilder .standard ()
54
- .withEndpointConfiguration (
55
- new AwsClientBuilder .EndpointConfiguration (API_ENDPOINT , "us-east-1" ))
56
- .build ();
57
53
private static final AmazonSQS SQS_CLIENT = AmazonSQSClientBuilder .defaultClient ();
58
54
private static final AmazonS3 S3_CLIENT = AmazonS3ClientBuilder .standard ().build ();
59
55
60
56
// Controls whether the current invocation session has been initialized. This should be reset on
61
57
// every invocation.
62
58
private boolean isSessionInitialized = false ;
59
+ // API Gateway Client. We create this in the constructor so we can recreate it if it goes away for
60
+ // some reason.
61
+ private AmazonApiGatewayManagementApi apiClient ;
63
62
64
63
public LambdaRequestHandler () {
65
64
// create CachedResources once for the entire container.
66
65
// This will only be called once in the initial creation of the lambda instance.
67
66
// Documentation: https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html
68
67
CachedResources .create ();
69
68
COLD_BOOT_END = Clock .systemUTC ().instant ();
69
+ this .apiClient =
70
+ AmazonApiGatewayManagementApiClientBuilder .standard ()
71
+ .withEndpointConfiguration (
72
+ new AwsClientBuilder .EndpointConfiguration (API_ENDPOINT , "us-east-1" ))
73
+ .build ();
70
74
}
71
75
72
76
/**
@@ -134,7 +138,7 @@ public String handleRequest(Map<String, String> lambdaInput, Context context) {
134
138
}
135
139
136
140
final ExceptionHandler exceptionHandler =
137
- new ExceptionHandler (outputAdapter , new AWSSystemExitHelper (connectionId , API_CLIENT ));
141
+ new ExceptionHandler (outputAdapter , new AWSSystemExitHelper (connectionId , this . apiClient ));
138
142
final TempDirectoryManager tempDirectoryManager = new AWSTempDirectoryManager ();
139
143
140
144
CodeExecutionManager codeExecutionManager = null ;
@@ -150,7 +154,7 @@ public String handleRequest(Map<String, String> lambdaInput, Context context) {
150
154
// Create and start thread that that will notify us if we're nearing the timeout limit
151
155
timeoutNotifierThread =
152
156
this .createTimeoutThread (
153
- context , outputAdapter , codeExecutionManager , connectionId , API_CLIENT );
157
+ context , outputAdapter , codeExecutionManager , connectionId , this . apiClient );
154
158
timeoutNotifierThread .start ();
155
159
156
160
// Initialize and start code execution
@@ -162,7 +166,7 @@ public String handleRequest(Map<String, String> lambdaInput, Context context) {
162
166
if (timeoutNotifierThread != null ) {
163
167
timeoutNotifierThread .interrupt ();
164
168
}
165
- this .shutDown (codeExecutionManager , connectionId , API_CLIENT );
169
+ this .shutDown (codeExecutionManager , connectionId , this . apiClient );
166
170
}
167
171
168
172
return "done" ;
@@ -188,6 +192,8 @@ private void initialize(Map<String, String> lambdaInput, String connectionId, Co
188
192
// /opt is the folder all layer files go into.
189
193
props .put ("sun.awt.fontconfig" , "/opt/fontconfig.properties" );
190
194
195
+ this .verifyApiClient (connectionId );
196
+
191
197
this .isSessionInitialized = true ;
192
198
}
193
199
@@ -214,7 +220,7 @@ private OutputAdapter createOutputAdapter(Map<String, String> lambdaInput)
214
220
if (connectionId == null ) {
215
221
throw new InternalFacingException (INVALID_INPUT , new Exception ("Missing connection ID" ));
216
222
}
217
- final AWSOutputAdapter awsOutputAdapter = new AWSOutputAdapter (connectionId , API_CLIENT );
223
+ final AWSOutputAdapter awsOutputAdapter = new AWSOutputAdapter (connectionId , this . apiClient );
218
224
219
225
try {
220
226
final ExecutionType executionType = ExecutionType .valueOf (lambdaInput .get ("executionType" ));
@@ -270,7 +276,7 @@ private CodeExecutionManager createExecutionManager(
270
276
compileList ,
271
277
tempDirectoryManager ,
272
278
contentManager ,
273
- new AWSSystemExitHelper (connectionId , API_CLIENT ));
279
+ new AWSSystemExitHelper (connectionId , this . apiClient ));
274
280
}
275
281
276
282
/**
@@ -371,4 +377,23 @@ private void cleanUpAWSResources(String connectionId, AmazonApiGatewayManagement
371
377
Logger .getLogger (MAIN_LOGGER ).removeHandler (allHandlers [i ]);
372
378
}
373
379
}
380
+
381
+ private void verifyApiClient (String connectionId ) {
382
+ GetConnectionRequest connectionRequest =
383
+ new GetConnectionRequest ().withConnectionId (connectionId );
384
+ try {
385
+ this .apiClient .getConnection (connectionRequest );
386
+ } catch (IllegalStateException e ) {
387
+ // This can occur if the api client has been shut down, which we have seen happen on occasion.
388
+ // Recreate the api client in this case. Log a warning so we can track when this happens.
389
+ Logger .getLogger (MAIN_LOGGER )
390
+ .warning (
391
+ "Received illegal state exception when trying to talk to API Gateway. Recreating api client." );
392
+ this .apiClient =
393
+ AmazonApiGatewayManagementApiClientBuilder .standard ()
394
+ .withEndpointConfiguration (
395
+ new AwsClientBuilder .EndpointConfiguration (API_ENDPOINT , "us-east-1" ))
396
+ .build ();
397
+ }
398
+ }
374
399
}
0 commit comments