Skip to content

Commit 1dcc10e

Browse files
John TompkinsRJ Lohan
authored andcommitted
Reinvocation only occurs locally if more than a minute of execution time remains (#188)
* Changing re-invocation calculation to reschedule after a minute elapses * Factor in 60 second guarantee of execution time * Account for negative callback time
1 parent 85ef205 commit 1dcc10e

File tree

3 files changed

+12
-9
lines changed

3 files changed

+12
-9
lines changed

src/main/java/com/amazonaws/cloudformation/LambdaWrapper.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
public abstract class LambdaWrapper<ResourceT, CallbackT> implements RequestStreamHandler {
8282

8383
private static final List<Action> MUTATING_ACTIONS = Arrays.asList(Action.CREATE, Action.DELETE, Action.UPDATE);
84+
private static final int INVOCATION_TIMEOUT_MS = 60000;
8485

8586
protected final Serializer serializer;
8687
protected LoggerProxy loggerProxy;
@@ -557,8 +558,10 @@ private boolean scheduleReinvocation(final HandlerRequest<ResourceT, CallbackT>
557558
// has enough runtime (with 20% buffer), we can reschedule from a thread wait
558559
// otherwise we re-invoke through CloudWatchEvents which have a granularity of
559560
// minutes
560-
if ((handlerResponse.getCallbackDelaySeconds() < 60)
561-
&& (context.getRemainingTimeInMillis() / 1000d) > handlerResponse.getCallbackDelaySeconds() * 1.2) {
561+
// This also guarantees a maximum of a minute of execution time per local
562+
// reinvocation
563+
if ((handlerResponse.getCallbackDelaySeconds() < 60) && context
564+
.getRemainingTimeInMillis() > Math.abs(handlerResponse.getCallbackDelaySeconds()) * 1200 + INVOCATION_TIMEOUT_MS) {
562565
log(String.format("Scheduling re-invoke locally after %s seconds, with Context {%s}",
563566
handlerResponse.getCallbackDelaySeconds(), reinvocationContext.toString()));
564567
sleepUninterruptibly(handlerResponse.getCallbackDelaySeconds(), TimeUnit.SECONDS);
@@ -567,7 +570,7 @@ private boolean scheduleReinvocation(final HandlerRequest<ResourceT, CallbackT>
567570

568571
log(String.format("Scheduling re-invoke with Context {%s}", reinvocationContext.toString()));
569572
try {
570-
int callbackDelayMinutes = handlerResponse.getCallbackDelaySeconds() / 60;
573+
int callbackDelayMinutes = Math.abs(handlerResponse.getCallbackDelaySeconds() / 60);
571574
this.scheduler.rescheduleAfterMinutes(context.getInvokedFunctionArn(), callbackDelayMinutes, request);
572575
} catch (final Throwable e) {
573576
this.log(String.format("Failed to schedule re-invoke, caused by %s", e.toString()));

src/main/java/com/amazonaws/cloudformation/proxy/ProgressEvent.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ public class ProgressEvent<ResourceT, CallbackT> {
5757

5858
/**
5959
* A callback will be scheduled with an initial delay of no less than the number
60-
* of seconds specified in the progress event. Set this value to <= 0 to
61-
* indicate no callback should be made.
60+
* of seconds specified in the progress event.
6261
*/
6362
private int callbackDelaySeconds;
6463

src/test/java/com/amazonaws/cloudformation/LambdaWrapperTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,6 @@ public void invokeHandler_withDefaultInjection_returnsInProgress() throws IOExce
846846
try (final InputStream in = loadRequestStream("create.request.json");
847847
final OutputStream out = new ByteArrayOutputStream()) {
848848
final Context context = getLambdaContext();
849-
850849
wrapper.handleRequest(in, out, context);
851850

852851
// verify output response
@@ -1008,7 +1007,8 @@ public void invokeHandler_localReinvokeWithSufficientRemainingTime() throws IOEx
10081007
final OutputStream out = new ByteArrayOutputStream()) {
10091008

10101009
final Context context = getLambdaContext();
1011-
when(context.getRemainingTimeInMillis()).thenReturn(60000); // ~1 minute
1010+
// give enough time to invoke again locally
1011+
when(context.getRemainingTimeInMillis()).thenReturn(75000);
10121012

10131013
wrapper.handleRequest(in, out, context);
10141014

@@ -1100,8 +1100,9 @@ public void invokeHandler_localReinvokeWithSufficientRemainingTimeForFirstIterat
11001100
final OutputStream out = new ByteArrayOutputStream()) {
11011101

11021102
final Context context = getLambdaContext();
1103-
when(context.getRemainingTimeInMillis()).thenReturn(60000, // 60 seconds
1104-
6000); // 6 seconds is <= 1.2 * 5 seconds requested, causes CWE reinvoke
1103+
// first remaining time allows for a local reinvocation, whereas the latter will
1104+
// force the second invocation to be via CWE
1105+
when(context.getRemainingTimeInMillis()).thenReturn(70000, 5000);
11051106

11061107
wrapper.handleRequest(in, out, context);
11071108

0 commit comments

Comments
 (0)