이 가이드에서는 흐름 단계가 실행될 때 발생하는 오류를 관리하는 방법을 설명합니다. 실패한 단계에서 해결을 위해 사용자 작업이 필요한지 또는 재시도할 수 있는지 지정할 수 있습니다.
- 실행 가능한 오류 반환: 사용자를 단계의 구성 카드로 안내하는 버튼을 오류 로그에 추가하여 오류를 해결하기 위해 입력을 수정할 수 있도록 합니다. 오류를 조치를 취할 수 있는 것으로 표시하려면
AddOnsResponseService.ErrorActionability.ACTIONABLE를 반환하세요. 오류를 조치를 취할 수 없는 것으로 표시하려면AddOnsResponseService.ErrorActionability.NOT_ACTIONABLE를 반환합니다. - 오류 후 단계 재시도: 흐름은 중지되기 전에 최대 5번까지 단계를 다시 실행하려고 시도합니다. 오류를 재시도할 수 있는 오류로 표시하려면
AddOnsResponseService.ErrorRetryability.RETRYABLE를 반환하세요. 재시도할 수 없는 오류를 표시하려면AddOnsResponseService.ErrorRetryability.NOT_RETRYABLE를 반환합니다.
칩, 하이퍼링크, 스타일이 지정된 텍스트를 사용하여 맞춤 오류 로그를 만들어 사용자에게 오류에 관한 자세한 컨텍스트를 제공할 수도 있습니다.
조치 가능한 오류 반환
다음 예에서는 사용자에게 음수를 묻는 단계를 빌드합니다. 사용자가 양수를 입력하면 단계에서 사용자에게 입력을 수정하라는 메시지를 표시하는 실행 가능한 오류를 반환합니다.
다음 매니페스트 파일은 단계의 입력, 출력, 구성 및 실행을 위해 호출할 함수를 정의합니다.
JSON
{
"timeZone": "America/Toronto",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"addOns": {
"common": {
"name": "Retry Errors Example",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
"useLocaleFromApp": true
},
"flows": {
"workflowElements": [
{
"id": "returnElementError",
"state": "ACTIVE",
"name": "Return Element Error Action",
"description": "To notify the user that some error has occurred",
"workflowAction": {
"inputs": [
{
"id": "value1",
"description": "The input from the user",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
}
],
"outputs": [
{
"id": "output_1",
"description": "The output",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
}
],
"onConfigFunction": "onConfiguration",
"onExecuteFunction": "onExecution"
}
}
]
}
}
}
다음 코드는 구성 카드를 빌드하고 오류 처리를 포함한 실행 로직을 처리합니다.
Apps Script
/**
* Returns a configuration card for the step.
* This card contains a text input field for the user.
*/
function onConfiguration() {
let section = CardService.newCardSection()
.addWidget(CardService.newTextInput()
.setFieldName("value1")
.setId("value1")
.setTitle("Please input negative numbers!"));
const card = CardService.newCardBuilder().addSection(section).build();
return card;
}
/**
* Gets an integer value from variable data, handling both string and integer formats.
* @param {Object} variableData The variable data object from the event.
* @return {number} The extracted integer value.
*/
function getIntValue(variableData) {
if (variableData.stringValues) {
return parseInt(variableData.stringValues[0]);
}
return variableData.integerValues[0];
}
/**
* Executes the step.
* If the user input is a positive number, it throws an error and returns an
* actionable error message. Otherwise, it returns the input as an output variable.
* @param {Object} e The event object from the workflow.
*/
function onExecution(e) {
try {
var input_value = getIntValue(e.workflow.actionInvocation.inputs["value1"]);
if (input_value > 0) {
throw new Error('Found invalid positive input value!');
}
// If execution is successful, return the output variable and a log.
const styledText_1 = AddOnsResponseService.newStyledText()
.setText("Execution completed, the number you entered was: ")
.addStyle(AddOnsResponseService.TextStyle.ITALIC)
.addStyle(AddOnsResponseService.TextStyle.UNDERLINE);
const styledText_2 = AddOnsResponseService.newStyledText().setText(input_value)
.setFontWeight(AddOnsResponseService.FontWeight.BOLD);
const workflowAction = AddOnsResponseService.newReturnOutputVariablesAction()
.setVariables({
"output_1": AddOnsResponseService.newVariableData().addStringValue(input_value)
})
.setLog(AddOnsResponseService.newWorkflowTextFormat()
.addTextFormatElement(
AddOnsResponseService.newTextFormatElement().setStyledText(styledText_1)
).addTextFormatElement(
AddOnsResponseService.newTextFormatElement().setStyledText(styledText_2)
));
let hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(workflowAction);
return AddOnsResponseService.newRenderActionBuilder().setHostAppAction(hostAppAction).build();
} catch (err) {
// If an error occurs, return an actionable error action.
Logger.log('An error occurred: ' + err.message);
const workflowAction = AddOnsResponseService.newReturnElementErrorAction()
// Sets the user-facing error message.
.setErrorLog(
AddOnsResponseService.newWorkflowTextFormat()
.addTextFormatElement(
AddOnsResponseService.newTextFormatElement().setText("Failed because of invalid input values!"))
)
// Makes the error actionable, allowing the user to correct the input.
.setErrorActionability(AddOnsResponseService.ErrorActionability.ACTIONABLE)
// Specifies that the error is not automatically retried.
.setErrorRetryability(AddOnsResponseService.ErrorRetryability.NOT_RETRYABLE);
let hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(workflowAction);
return AddOnsResponseService.newRenderActionBuilder().setHostAppAction(hostAppAction).build();
}
}
오류 발생 후 단계 재시도
다음 예시에서는 임시 장애를 시뮬레이션하는 단계를 빌드합니다. 오류가 발생하면 단계를 다시 시도할 수 있는 오류가 반환되어 흐름에서 단계를 다시 실행합니다.
매니페스트 파일은 단계를 정의합니다.
JSON
{
"timeZone": "America/Toronto",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"addOns": {
"common": {
"name": "Retry Errors Example",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
"useLocaleFromApp": true
},
"flows": {
"workflowElements": [
{
"id": "retryError",
"state": "ACTIVE",
"name": "Retry an error",
"description": "Simulates a temporary failure and retries the step.",
"workflowAction": {
"inputs": [
{
"id": "value1",
"description": "Any input value",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
}
],
"outputs": [
{
"id": "output_1",
"description": "The output",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
}
],
"onConfigFunction": "onRetryConfiguration",
"onExecuteFunction": "onRetryExecution"
}
}
]
}
}
}
다음 코드는 구성 카드를 빌드하고 재시도 로직을 처리합니다.
Apps Script
/**
* Returns a configuration card for the step.
* This card contains a text input field for the user.
*/
function onRetryConfiguration() {
let section = CardService.newCardSection()
.addWidget(CardService.newTextInput()
.setFieldName("value1")
.setId("value1")
.setTitle("Enter any value"));
const card = CardService.newCardBuilder().addSection(section).build();
return card;
}
/**
* Executes the step and simulates a transient error.
* This function fails 80% of the time. When it fails, it returns an
* error that can be retried.
* @param {Object} e The event object from the workflow.
*/
function onRetryExecution(e) {
try {
// Simulate a transient error that fails 80% of the time.
if (Math.random() < 0.8) {
throw new Error('Simulated transient failure!');
}
// If execution is successful, return the output variable and a log.
var input_value = e.workflow.actionInvocation.inputs["value1"].stringValues[0];
const styledText = AddOnsResponseService.newStyledText()
.setText(`Execution succeeded for input: ${input_value}`);
const workflowAction = AddOnsResponseService.newReturnOutputVariablesAction()
.setVariables({
"output_1": AddOnsResponseService.newVariableData().addStringValue(input_value)
})
.setLog(AddOnsResponseService.newWorkflowTextFormat()
.addTextFormatElement(
AddOnsResponseService.newTextFormatElement().setStyledText(styledText)
));
let hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(workflowAction);
return AddOnsResponseService.newRenderActionBuilder().setHostAppAction(hostAppAction).build();
} catch (err) {
// If a transient error occurs, return an error message saying the step tries to run again.
Logger.log('A error occurred, trying to run the step again: ' + err.message);
const workflowAction = AddOnsResponseService.newReturnElementErrorAction()
// Sets the user-facing error message.
.setErrorLog(
AddOnsResponseService.newWorkflowTextFormat()
.addTextFormatElement(
AddOnsResponseService.newTextFormatElement().setText("A temporary error occurred. The step will be retried."))
)
// Makes the error not actionable by the user.
.setErrorActionability(AddOnsResponseService.ErrorActionability.NOT_ACTIONABLE)
// Specifies that the error is automatically retried.
.setErrorRetryability(AddOnsResponseService.ErrorRetryability.RETRYABLE);
let hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(workflowAction);
return AddOnsResponseService.newRenderActionBuilder().setHostAppAction(hostAppAction).build();
}
}