Skip to content

Commit 9899a67

Browse files
authored
fix: correct Cloud Event retry functionality (#326)
* fix: Correct exception handling for CloudEvents A previous change resulted broke exception handling for cloud events so that an exception from the function would not result in a failure response code. Correct error handling for CloudEvents and add a test to cover this case to avoid future breakages. * fix: Do not add execution_id field if logging is disabled Fix logger to not add field if logging is disabled.
1 parent d6f7186 commit 9899a67

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

invoker/core/src/main/java/com/google/cloud/functions/invoker/BackgroundFunctionExecutor.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,7 @@ private <CloudEventT> void serviceCloudEvent(HttpServletRequest req) throws Exce
364364
// ServiceLoader.load
365365
// will throw ServiceConfigurationError. At this point we're still running with the default
366366
// context ClassLoader, which is the system ClassLoader that has loaded the code here.
367-
try {
368-
executionIdUtil.storeExecutionId(req);
369-
runWithContextClassLoader(() -> executor.serviceCloudEvent(reader.toEvent(data -> data)));
370-
} catch (Throwable t) {
371-
logger.log(Level.SEVERE, "Failed to execute " + executor.functionName(), t);
372-
} finally {
373-
executionIdUtil.removeExecutionId();
374-
}
367+
runWithContextClassLoader(() -> executor.serviceCloudEvent(reader.toEvent(data -> data)));
375368
// The data->data is a workaround for a bug fixed since Milestone 4 of the SDK, in
376369
// https://github.com/cloudevents/sdk-java/pull/259.
377370
}

invoker/core/src/main/java/com/google/cloud/functions/invoker/gcf/JsonLogHandler.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
public final class JsonLogHandler extends Handler {
1919
private static final String SOURCE_LOCATION_KEY = "\"logging.googleapis.com/sourceLocation\": ";
20+
private static final String LOG_EXECUTION_ID_ENV_NAME = "LOG_EXECUTION_ID";
2021

2122
private static final String DEBUG = "DEBUG";
2223
private static final String INFO = "INFO";
@@ -108,9 +109,11 @@ private static void appendSourceLocation(StringBuilder json, LogRecord record) {
108109
}
109110

110111
private void appendExecutionId(StringBuilder json, LogRecord record) {
111-
json.append("\"execution_id\": \"")
112-
.append(executionIdByThreadMap.get(Integer.toString(record.getThreadID())))
113-
.append("\", ");
112+
if (executionIdLoggingEnabled()) {
113+
json.append("\"execution_id\": \"")
114+
.append(executionIdByThreadMap.get(Integer.toString(record.getThreadID())))
115+
.append("\", ");
116+
}
114117
}
115118

116119
private static String escapeString(String s) {
@@ -142,4 +145,8 @@ public void addExecutionId(long threadId, String executionId) {
142145
public void removeExecutionId(long threadId) {
143146
executionIdByThreadMap.remove(Long.toString(threadId));
144147
}
148+
149+
private boolean executionIdLoggingEnabled() {
150+
return Boolean.parseBoolean(System.getenv().getOrDefault(LOG_EXECUTION_ID_ENV_NAME, "false"));
151+
}
145152
}

invoker/core/src/test/java/com/google/cloud/functions/invoker/IntegrationTest.java

+37
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,43 @@ public void nativeCloudEvent() throws Exception {
577577
ImmutableList.of(cloudEventsStructuredTestCase, cloudEventsBinaryTestCase));
578578
}
579579

580+
/** Tests a CloudEvent being handled by a CloudEvent handler throws exception */
581+
@Test
582+
public void nativeCloudEventException() throws Exception {
583+
String exceptionExpectedOutput =
584+
"\"severity\": \"ERROR\", \"logging.googleapis.com/sourceLocation\": {\"file\":"
585+
+ " \"com/google/cloud/functions/invoker/BackgroundFunctionExecutor.java\", \"method\":"
586+
+ " \"service\"}, \"execution_id\": \""
587+
+ EXECUTION_ID
588+
+ "\", "
589+
+ "\"message\": \"Failed to execute"
590+
+ " com.google.cloud.functions.invoker.testfunctions.ExceptionBackground\\n"
591+
+ "java.lang.RuntimeException: exception thrown for test";
592+
File snoopFile = snoopFile();
593+
CloudEvent cloudEvent = sampleCloudEvent(snoopFile);
594+
EventFormat jsonFormat =
595+
EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE);
596+
String cloudEventJson = new String(jsonFormat.serialize(cloudEvent), UTF_8);
597+
598+
// A CloudEvent using the "structured content mode", where both the metadata and the payload
599+
// are in the body of the HTTP request.
600+
TestCase cloudEventsStructuredTestCase =
601+
TestCase.builder()
602+
.setRequestText(cloudEventJson)
603+
.setHttpContentType("application/cloudevents+json; charset=utf-8")
604+
.setHttpHeaders(ImmutableMap.of(EXECUTION_ID_HTTP_HEADER, EXECUTION_ID))
605+
.setExpectedResponseCode(500)
606+
.setExpectedOutput(exceptionExpectedOutput)
607+
.build();
608+
609+
testFunction(
610+
SignatureType.CLOUD_EVENT,
611+
fullTarget("ExceptionBackground"),
612+
ImmutableList.of(),
613+
ImmutableList.of(cloudEventsStructuredTestCase),
614+
Collections.emptyMap());
615+
}
616+
580617
@Test
581618
public void nested() throws Exception {
582619
String testText = "sic transit gloria mundi";

0 commit comments

Comments
 (0)