microsoft / durabletask-java

Java SDK for Durable Functions and the Durable Task Framework
MIT License
13 stars 7 forks source link

Proper error message in case of failures #112

Closed akshaykumars10 closed 1 year ago

akshaykumars10 commented 1 year ago

We use a custom instance id while creating instances of our orchestrator function. If the instance_id already exists, we are getting an UNKNOWN exception in the error message. This makes debugging things a little harder. Sample error log with java: System.Private.CoreLib: Exception while executing function: Functions.WorkflowHttpStarter. System.Private.CoreLib: Result: Failure [2023-02-15T09:46:44.346Z] Exception: StatusRuntimeException: UNKNOWN: Exception was thrown by handler. [2023-02-15T09:46:44.346Z] Stack: java.lang.reflect.InvocationTargetException In Python, we get a proper error message like this: Exception: Exception: {'Message': 'Something went wrong while processing your request', 'ExceptionMessage': 'An Orchestration instance with the status Running already exists.', 'ExceptionType': 'System.InvalidOperationException Can we fix this?

cgillum commented 1 year ago

@kaibocai @shreyas-gopalakrishna can one of you look at this? This may require a change in the durable functions extension here to return a more specific gRPC error message, which we should then translate into a more Java-friendly error message in the Java SDK.

kamperiadis commented 1 year ago

I can start taking a look at this

kamperiadis commented 1 year ago

@akshaykumars10 Can you please share a sample of how you were able to get this error? I want to reproduce it the same way you did

akshaykumars10 commented 1 year ago

Hi @kamperiadis I am using an HTTP Starter function to create instances of my Orchestrator function. We are passing the customer instance_id as a query param while calling the HTTP Starter. HTTP Starter will use this instance id to create an instance of our orchestrator function. This call fails with the above error in logs when we use an instance id that already exists. This is our HTTP Starter function:

@FunctionName("WorkflowHttpStarter")
 public HttpResponseMessage workflowHttpStarter(
@HttpTrigger(name = "req", methods = {HttpMethod.POST, HttpMethod.DELETE}) HttpRequestMessage<Optional<String>> req, @DurableClientInput(name = "durableContext") DurableClientContext durableContext,
            final ExecutionContext context) throws ParseException {`

        HttpMethod method = req.getHttpMethod();
        Map<String, String> queryParams = req.getQueryParameters();
        String instanceId = null;
        if (queryParams.containsKey("runId")) {
            instanceId = queryParams.get("runId");
        } else if (queryParams.containsKey("workflowId")) {
            instanceId = queryParams.get("workflowId");
        }

        if (method == HttpMethod.POST) {
            // Fetch the payload
            Optional<String> os = req.getBody();
            JSONObject jsonBody = null;
            if (os.isPresent()) {
                String jsonBodyStr = os.get();
                JSONParser parser = new JSONParser();
                jsonBody = (JSONObject) parser.parse(jsonBodyStr);
                context.getLogger().info(instanceId +": found this body: " + jsonBody.toString());
            }

            // We will receive orchetrator function name in query param
            String orchestratorName = queryParams.get("orchestratorName");
            context.getLogger().info(instanceId + ": received a request to create an instance of: " + orchestratorName);

            // Fetch the custom instanceId

            DurableTaskClient client = durableContext.getClient();
            // context.getLogger().info("Found thse " + instanceId + " " + orchestratorName + " " + jsonBody.toString());
            instanceId = client.scheduleNewOrchestrationInstance(orchestratorName, jsonBody, instanceId);
            context.getLogger().info(instanceId + ": Created new Java orchestration with instance ID = " + instanceId);
            return durableContext.createCheckStatusResponse(req, instanceId);
        } 
        else if (method == HttpMethod.DELETE) {
            if (queryParams.containsKey("runId")) {
                instanceId = queryParams.get("runId");
            } else if (queryParams.containsKey("workflowId")) {
                instanceId = queryParams.get("workflowId");
            }
            DurableTaskClient client = durableContext.getClient();
            client.terminate(instanceId, "Terminated instance via API");
            context.getLogger().info(instanceId + ": Terminated Java orchestration with instance ID = " + instanceId);
        }
        return durableContext.createCheckStatusResponse(req, instanceId);

    }

Please let me know if you need more details.

kaibocai commented 1 year ago

@akshaykumars10, the fix is released in Durable Extension 2.9.6, please customized your DF extension to 2.9.6 to try it out. You can do that follow the steps here https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-extension-upgrade#manually-upgrade-the-durable-functions-extension.

Closing the issue.