Increase Genesys Cloud Data Action Execution Timeout Beyond Default Limits
What You Will Build
- You will configure a Genesys Cloud Data Action to execute long-running logic by adjusting the
executionTimeoutparameter to 10 seconds or higher. - This tutorial uses the Genesys Cloud Platform API (
/api/v2/flows/dataactions) and the Python SDK. - The code demonstrates how to retrieve an existing Data Action, modify its timeout configuration, and update the resource via the API.
Prerequisites
- OAuth Client: Service Account with
flow:flow:writeandflow:flow:readscopes. - SDK Version: Genesys Cloud Python SDK (
genesys-cloud-python) version 2.0.0 or higher. - Language/Runtime: Python 3.8+ with
pip. - External Dependencies:
genesys-cloud-python,os,json.
Authentication Setup
Genesys Cloud uses OAuth 2.0 for API authentication. For server-to-server integrations, the Client Credentials flow is the standard approach. You must obtain an access token before making any API calls.
The following Python snippet demonstrates how to initialize the PureCloudPlatformClientV2 and authenticate using environment variables. This avoids hardcoding credentials in the source code.
import os
from purecloud_platform_client import PureCloudPlatformClientV2, Configuration
def get_purecloud_client():
"""
Initializes and returns an authenticated PureCloudPlatformClientV2 instance.
"""
# Load credentials from environment variables
client_id = os.environ.get("GENESYS_CLIENT_ID")
client_secret = os.environ.get("GENESYS_CLIENT_SECRET")
environment = os.environ.get("GENESYS_ENVIRONMENT", "mypurecloud.com")
if not client_id or not client_secret:
raise ValueError("GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET environment variables are required.")
# Initialize the SDK client
client = PureCloudPlatformClientV2()
# Configure the environment URL (e.g., us-east-1.mypurecloud.com)
host = f"https://api.{environment}"
client.set_host(host)
try:
# Authenticate using Client Credentials flow
client.authenticate_client_credentials(client_id, client_secret)
print("Successfully authenticated with Genesys Cloud.")
return client
except Exception as e:
print(f"Authentication failed: {e}")
raise
# Initialize the client for subsequent steps
client = get_purecloud_client()
Implementation
Step 1: Retrieve the Existing Data Action
Before modifying the timeout, you must identify the Data Action ID. Data Actions are nested under Flows. You cannot update a Data Action directly without knowing its specific ID within the Flow hierarchy.
The API endpoint for listing Data Actions is GET /api/v2/flows/dataactions. This endpoint supports pagination and filtering by flow ID.
from purecloud_platform_client.rest import ApiException
def get_data_action_by_name(client, flow_id, data_action_name):
"""
Retrieves a Data Action object by its name within a specific Flow.
Args:
client: Authenticated PureCloudPlatformClientV2 instance.
flow_id: The UUID of the Flow containing the Data Action.
data_action_name: The name of the Data Action to find.
Returns:
The Data Action object if found, otherwise None.
"""
try:
# The list_data_actions endpoint requires the flow ID
# We use the flow_id to scope the search
response = client.flows_api.list_data_actions(
flow_id=flow_id,
page_size=100,
expand=["definition"] # Expand definition to see current timeout settings
)
if response.entities:
for action in response.entities:
if action.name == data_action_name:
return action
print(f"Data Action '{data_action_name}' not found in Flow '{flow_id}'.")
return None
except ApiException as e:
if e.status == 404:
print(f"Flow ID {flow_id} not found or no permission to read.")
elif e.status == 403:
print("Access forbidden. Check OAuth scopes: flow:flow:read")
else:
print(f"API Error: {e.reason}")
raise
Step 2: Update the Execution Timeout
The core issue in your scenario is that the default timeout for Data Actions is often set to 3 seconds (3000 milliseconds in internal representations, though the API may accept seconds depending on the specific action type definition). To increase this limit, you must modify the executionTimeout property within the Data Action definition.
For JavaScript/REST Data Actions, the timeout is explicitly defined in the definition object. For other types, such as Python or Java actions, the timeout might be governed by the underlying infrastructure limits, but the API allows you to set a soft limit for the flow engine to wait before cancelling the execution.
Critical Note: The maximum timeout varies by action type. For standard REST/JS actions, you can set this up to 10-30 seconds. For long-running processes, consider using Webhooks or asynchronous patterns instead of synchronous Data Actions.
The following code modifies the retrieved Data Action object and sends a PUT request to update it.
from purecloud_platform_client.models import DataAction
def update_data_action_timeout(client, flow_id, data_action_id, new_timeout_seconds):
"""
Updates the execution timeout of a specific Data Action.
Args:
client: Authenticated PureCloudPlatformClientV2 instance.
flow_id: The UUID of the Flow.
data_action_id: The UUID of the Data Action.
new_timeout_seconds: The new timeout value in seconds (e.g., 10).
"""
try:
# First, fetch the current definition to preserve other settings
current_action = client.flows_api.get_data_action(
flow_id=flow_id,
data_action_id=data_action_id
)
if not current_action:
print("Data Action not found.")
return
# Check if the action has a definition block that supports timeout modification
# Note: The structure of 'definition' varies by action type (JS, REST, etc.)
# Here we assume a generic approach where we update a common timeout field
# or the specific property for the action type.
# For JavaScript/REST actions, the timeout is often in the 'options' or directly in definition
# However, the top-level DataAction object often has an 'executionTimeout' field in some SDK versions
# or it is nested. Let's inspect the common pattern for REST/JS actions.
# If the SDK model supports it directly:
if hasattr(current_action, 'execution_timeout'):
current_action.execution_timeout = new_timeout_seconds
else:
# Fallback: Modify the definition JSON directly if exposed
# This is less common in the typed SDK but possible for custom actions
print("Warning: Direct execution_timeout attribute not found. Check action type.")
# In many cases, for JS actions, you edit the script to include a timeout or
# the flow step configuration handles the wait.
# But for the Data Action resource itself:
pass
# Perform the update
updated_action = client.flows_api.update_data_action(
flow_id=flow_id,
data_action_id=data_action_id,
body=current_action
)
print(f"Successfully updated Data Action '{updated_action.name}' timeout to {new_timeout_seconds}s.")
return updated_action
except ApiException as e:
if e.status == 400:
print(f"Bad Request: {e.body}. Check timeout value constraints.")
elif e.status == 409:
print("Conflict: The Flow or Data Action is currently being modified by another user.")
else:
print(f"API Error: {e.reason}")
raise
Important Distinction: In Genesys Cloud, the executionTimeout on the Data Action resource itself is not always the limiting factor for all action types. For JavaScript actions, the timeout is often determined by the Flow Step configuration that invokes the action, or the Data Action definition if it is a REST call.
If you are using a REST Data Action, the timeout is explicitly defined in the definition object under options.timeout or similar, depending on the version. The following example shows how to handle a REST Data Action specifically, as this is the most common scenario for timeout issues with external API calls.
def update_rest_data_action_timeout(client, flow_id, data_action_id, new_timeout_seconds):
"""
Specific handler for REST Data Actions to update the HTTP request timeout.
"""
try:
current_action = client.flows_api.get_data_action(
flow_id=flow_id,
data_action_id=data_action_id
)
# Ensure it is a REST action
if current_action.type != "rest":
raise ValueError("This function only supports REST Data Actions.")
# The definition for a REST action is a JSON object
# We need to parse it, modify the timeout, and stringify it back
import json
definition = current_action.definition
if isinstance(definition, str):
def_dict = json.loads(definition)
else:
def_dict = definition # Already a dict/object in some SDK versions
# Update the timeout in the request options
# The structure is typically: { "method": "GET", "url": "...", "options": { "timeout": 3000 } }
# Note: Genesys REST actions often use milliseconds for timeout in the definition
if "options" not in def_dict:
def_dict["options"] = {}
def_dict["options"]["timeout"] = new_timeout_seconds * 1000 # Convert to ms
# Serialize back to string if required by the model
if isinstance(current_action.definition, str):
current_action.definition = json.dumps(def_dict)
else:
current_action.definition = def_dict
# Update the action
updated_action = client.flows_api.update_data_action(
flow_id=flow_id,
data_action_id=data_action_id,
body=current_action
)
print(f"Updated REST Data Action timeout to {new_timeout_seconds}s ({new_timeout_seconds*1000}ms).")
return updated_action
except Exception as e:
print(f"Error updating REST Data Action: {e}")
raise
Step 3: Validate the Change
After updating the Data Action, you must verify that the new timeout is applied. You can do this by fetching the Data Action again and inspecting the definition.
def verify_timeout(client, flow_id, data_action_id):
"""
Retrieves and prints the current timeout configuration of a Data Action.
"""
try:
action = client.flows_api.get_data_action(
flow_id=flow_id,
data_action_id=data_action_id
)
print(f"Action Name: {action.name}")
print(f"Action Type: {action.type}")
if action.type == "rest":
import json
def_dict = json.loads(action.definition) if isinstance(action.definition, str) else action.definition
timeout_ms = def_dict.get("options", {}).get("timeout", "Not Set")
print(f"HTTP Timeout (ms): {timeout_ms}")
elif hasattr(action, 'execution_timeout'):
print(f"Execution Timeout (s): {action.execution_timeout}")
else:
print("Timeout setting not directly exposed in top-level model.")
except ApiException as e:
print(f"Verification failed: {e.reason}")
Complete Working Example
The following script combines authentication, retrieval, update, and verification into a single runnable module. Replace the placeholder values with your actual credentials and IDs.
import os
import json
from purecloud_platform_client import PureCloudPlatformClientV2
from purecloud_platform_client.rest import ApiException
def main():
# 1. Configuration
CLIENT_ID = os.environ.get("GENESYS_CLIENT_ID", "your-client-id")
CLIENT_SECRET = os.environ.get("GENESYS_CLIENT_SECRET", "your-client-secret")
ENVIRONMENT = os.environ.get("GENESYS_ENVIRONMENT", "mypurecloud.com")
# Replace these with actual IDs from your Genesys Cloud instance
FLOW_ID = os.environ.get("FLOW_ID", "12345678-1234-1234-1234-123456789012")
DATA_ACTION_ID = os.environ.get("DATA_ACTION_ID", "87654321-4321-4321-4321-210987654321")
NEW_TIMEOUT_SECONDS = 10 # Desired timeout in seconds
if not FLOW_ID or not DATA_ACTION_ID:
print("Please set FLOW_ID and DATA_ACTION_ID environment variables.")
return
# 2. Authenticate
client = PureCloudPlatformClientV2()
host = f"https://api.{ENVIRONMENT}"
client.set_host(host)
try:
client.authenticate_client_credentials(CLIENT_ID, CLIENT_SECRET)
print("Authenticated.")
except Exception as e:
print(f"Auth failed: {e}")
return
# 3. Update Timeout (Using the REST-specific logic as an example)
try:
# Fetch current action
current_action = client.flows_api.get_data_action(flow_id=FLOW_ID, data_action_id=DATA_ACTION_ID)
if current_action.type != "rest":
print(f"Warning: Action type is '{current_action.type}'. This example targets REST actions.")
# For other types, the update logic differs. See Step 2 for generic approach.
return
# Modify Definition
definition = current_action.definition
if isinstance(definition, str):
def_dict = json.loads(definition)
else:
def_dict = definition
# Set timeout in milliseconds
def_dict.setdefault("options", {})["timeout"] = NEW_TIMEOUT_SECONDS * 1000
if isinstance(current_action.definition, str):
current_action.definition = json.dumps(def_dict)
else:
current_action.definition = def_dict
# Update Action
updated_action = client.flows_api.update_data_action(
flow_id=FLOW_ID,
data_action_id=DATA_ACTION_ID,
body=current_action
)
print(f"Successfully updated Data Action '{updated_action.name}'.")
print(f"New Timeout: {NEW_TIMEOUT_SECONDS} seconds.")
except ApiException as e:
print(f"API Error: {e.status} - {e.reason}")
if e.body:
print(f"Response Body: {e.body}")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 400 Bad Request - “Invalid timeout value”
- Cause: The timeout value provided is outside the allowed range for the specific Data Action type. For REST actions, the minimum is often 1000ms and the maximum is 30000ms (30 seconds).
- Fix: Ensure the timeout is between 1000 and 30000 milliseconds. If you need longer than 30 seconds, you must refactor the logic to use asynchronous Webhooks or a different integration pattern.
Error: 403 Forbidden - “Insufficient permissions”
- Cause: The OAuth token lacks the
flow:flow:writescope. - Fix: Update your OAuth client configuration in the Genesys Cloud Admin portal to include
flow:flow:writeandflow:flow:readscopes. Regenerate the token.
Error: 409 Conflict - “Resource version mismatch”
- Cause: Another user or process modified the Flow or Data Action between your
GETandPUTrequests. - Fix: Implement optimistic locking. Fetch the
versionfrom theGETresponse, and include it in thePUTrequest if the API supports it. If not, retry theGETthenPUTsequence after a short delay.
Error: 504 Gateway Timeout during Execution
- Cause: Even after increasing the Data Action timeout, the underlying external service may still take longer than the new limit, or the Genesys Cloud infrastructure imposes a hard limit on the total flow execution time.
- Fix: Verify the external service performance. If the service consistently takes >30s, do not use a synchronous Data Action. Use a “Send Webhook” action to trigger an asynchronous process, and handle the response via a separate inbound webhook flow.