How to end a workflow automatically after certain time

Which IIQ version are you inquiring about?

8.4

Please share any images or screenshots, if relevant.


Hi Experts,

I have a custom workflow that launches a custom XHTML page for uploading files to the server. However, each time a user starts the workflow, it creates an active task that never completes. I would like to kindly ask if there is a recommended way to avoid this issue.

Hi @Bernardc

The reason the task is staying open is because the workflow doesn’t know when to finish. You’re using a custom XHTML form (fileUpload.xhtml), but there’s no return value or action telling the workflow to move forward.

To fix this:

  1. In the workflow step, set the Return value to something like submitted.
  2. In your XHTML form, make sure the submit button includes the same outcome:
<sp:button value="Submit" outcome="submitted"/>
  1. In the workflow, add a transition that says:
  2. 5.If outcome is submitted, go to End.

This way, when the user submits the form, the workflow knows it’s done and will close the task.

Hi @SaidurgaMallela ,

I created a button:

<p:commandButton value="Exit"
style="margin-top:0.5rem; background-color:#007ad9; color:white; padding:0.5rem 1rem; border:none; border-radius:4px;"
onmouseover="this.style.backgroundColor='#005ea3';"
onmouseout="this.style.backgroundColor='#007ad9';"
 outcome="submitted" />	

Added return value:

In my transition:

Am I doing it correctly? Currently the button does not exit the workflow yet.

Edit

Since this thread was auto-closed, I can’t add a comment, so I’m putting it here. The accepted solution is not a good approach. Deleting your workflow case just to “end” it is like using a sledgehammer to swat a fly. You’re hiding the problem with your form and workflow’s design instead of solving it.

/Edit

I know basically nothing about writing custom forms using XHTML, but I can tell those aren’t the same thing. I suspect the sp:button is a SailPoint-provided tag while the p:commandButton looks like it might not be. If I’m right, the outcome attribute would only be relevant to an sp:button and at best would have no effect. The sp:button presumably supports this attribute and SailPoint’s code automatically sets some property named outcome somewhere when that button is used to submit the form.

In your transition, your BeanShell code is setting a variable named outcome to the value “submitted” instead of checking for equality. Assuming that the outcome is accessible through a variable named outcome (please note I have no idea if it would be), then you would write "submitted".equals("outcome") to check for equality.

Hi All,

Instead of returning a value from the form and transitioning the workflow to the end, I developed a rule that deletes the task based on its name pattern. This approach has resolved the issue.

Here is the rule:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="1750905277922" id="0ac928ce979f17e08197aa164de112ef" language="beanshell" modified="1750907840910" name="Delete Task by Name Rule 2" significantModified="1750907840910" type="Workflow">
  <Description>
        Rule to delete tasks by name. This rule can be used to clean up completed or failed tasks.
    </Description>
  <Signature returnType="void">
    <Inputs>
      <Argument name="context" type="sailpoint.api.SailPointContext"/>
    </Inputs>
  </Signature>
  <Source>
        
import sailpoint.object.TaskResult;
import sailpoint.object.Filter;
import sailpoint.object.QueryOptions;
import java.util.List;
import java.util.Iterator;

try {
    // Hard-coded task name pattern
    String taskNamePattern = "input name pattern here";
    
    System.out.println("Starting Delete Task Rule for tasks containing: " + taskNamePattern);
    
    if (taskNamePattern == null || taskNamePattern.trim().isEmpty()) {
        System.out.println("Task name pattern is null or empty");
        return;
    }
    
    // Create filter to find tasks containing the pattern
    Filter filter = Filter.like("name", taskNamePattern);
    QueryOptions qo = new QueryOptions();
    qo.addFilter(filter);
    
    // Get all TaskResult objects with names containing the pattern
    List taskResults = context.getObjects(TaskResult.class, qo);
    
    if (taskResults == null || taskResults.isEmpty()) {
        System.out.println("No tasks found containing: " + taskNamePattern);
        return;
    }
    
    System.out.println("Found " + taskResults.size() + " task(s) containing: " + taskNamePattern);
    
    int deletedCount = 0;
    
    // Iterate through and delete each task
    for (TaskResult taskResult : taskResults) {
        try {
            System.out.println("Deleting task: " + taskResult.getName() + " (ID: " + taskResult.getId() + ")");
            
            // Delete the task
            context.removeObject(taskResult);
            deletedCount++;
            
            System.out.println("Successfully deleted task: " + taskResult.getName());
            
        } catch (Exception e) {
            System.out.println("Error deleting task: " + taskResult.getName() + " - " + e.getMessage());
        }
    }
    
    // Commit the changes
    context.commitTransaction();
    
    System.out.println("Delete Task Rule completed. Deleted " + deletedCount + " task(s) containing: " + taskNamePattern);
    
} catch (Exception e) {
    System.out.println("Error in Delete Task by Name Rule: " + e.getMessage());
    context.rollbackTransaction();
    throw e;
}
        
    </Source>
</Rule>