Documentation

Creating a New Dispatch Task Executor

Each Dispatch Task is created by implementing the DispatchTaskExecutor interface and can execute any logic. While Liferay DXP provides multiple out-of-the-box executors, you can create your own. Once created and deployed, you can add Dispatch Tasks to a Liferay instance.

Follow these steps to create your own implementation of the DispatchTaskExecutor interface:

  1. OSGI Component: Declare the module a Component within the OSGi framework using the @Component annotation.

  2. Service: Identify the module as a DispatchTaskExecutor.class service within the @Component annotation.

  3. OSGi Properties: Add the following properties to the @Component annotation.

    • dispatch.task.executor.name: defines the string used for the executor’s name in the Dispatch UI.

      Note

      If you want your Dispatch Task to use localized names, add a language key value for the dispatch.task.executor.name property to the module’s resources/content/Language.properties file.

    • dispatch.task.executor.type: defines a unique type value to match the right Dispatch Task Executor and Dispatch Trigger.

      Note

      Values must be unique to ensure the correct executor matches. If a value is not unique, the log displays an error on startup indicating which executors have the same property value.

  4. DispatchTaskExecutor: Implement the DispatchTaskExecutor interface or extend an implementation of it (e.g., BaseDispatchTaskExecutor).

    Important

    Implementations of the DispatchTaskExecutor interface must handle status logs for Dispatch tasks, because the Dispatch framework depends on those logs to control the concurrent execution of tasks.

    For your convenience, Liferay provides the BaseDispatchTaskExecutor abstract class that logs the Dispatch task’s status as IN PROGRESS, SUCCESSFUL, or FAILED.

  5. Methods: If you’re implementing the DispatchTaskExecutor interface directly, override its execute() method to implement custom logic. If instead you’re extending the BaseDispatchTaskExecutor abstract class, override its doExecute() method.

    Note

    The getName() method is deprecated and replaced by the dispatch.task.executor.name property.

    Tip

    You can use the dispatchTrigger.getDispatchTaskSettings() method to fetch properties set in the Dispatch Task’s Settings editor.

The following sample module demonstrates how to create and deploy a custom Dispatch Task Executor to a Liferay instance.

Deploying the Sample Dispatch Task Executor

Follow these steps to download, build, and deploy the sample Dispatch Task Executor to a new docker container:

  1. Start a new Liferay Docker container.

    docker run -it -m 8g -p 8080:8080 liferay/dxp:7.3.10-dxp-1
    
  2. Download and unzip the example module.

    curl https://learn.liferay.com/docs/dxp/latest/en/developing-applications/core-frameworks/dispatch-framework/liferay-s7a3.zip -O
    
    unzip liferay-s7a3.zip -d liferay-s7a3
    
  3. Run this gradlew command to build the JAR file and deploy it to your new Docker container:

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    

    The JAR is generated in the build/libs folder (i.e., s7a3-impl/build/libs/com.acme.s7a3.impl-1.0.0).

  4. Confirm the module was successfully deployed and started via the container console.

    Processing com.acme.s7a3.impl-1.0.0.jar
    STARTED com.acme.s7a3.impl-1.0.0 [1656]
    
  5. Verify the module is working by using it to add a new Dispatch Task to your Liferay instance.

    Add a new Dispatch Task using the new template.

    Once you’ve created the task, click on Run Now.

    Click Run Now for your new Dispatch Task.

    If successful, it should print the following message to the console when executed.

    INFO [liferay/dispatch/executor-2][S7A3DispatchTaskExecutor:30] Invoking #doExecute(DispatchTrigger, DispatchTaskExecutorOutput)
    

    You can also click the Dispatch Task and go to the Logs tab to see a list of all previous runs.

    View and manage logs for your Dispatch Task.

Code for the Sample Dispatch Task Executor

@Component(
	property = {
		"dispatch.task.executor.name=s7a3", "dispatch.task.executor.type=s7a3"
	},
	service = DispatchTaskExecutor.class
)
public class S7A3DispatchTaskExecutor extends BaseDispatchTaskExecutor {

	@Override
	public void doExecute(
			DispatchTrigger dispatchTrigger,
			DispatchTaskExecutorOutput dispatchTaskExecutorOutput)
		throws IOException, PortalException {

		if (_log.isInfoEnabled()) {
			_log.info(
				"Invoking #doExecute(DispatchTrigger, " +
					"DispatchTaskExecutorOutput)");
		}
	}

	@Override
	public String getName() {
		return "s7a3";
	}

	private static final Log _log = LogFactoryUtil.getLog(
		S7A3DispatchTaskExecutor.class);

}

The module is declared an OSGi @Component and defines two properties: dispatch.task.executor.name and dispatch.task.executor.type. It then identifies the module as a DispatchTaskExecutor.class service.

Following the @Component annotation, the module extends the BaseDispatchTaskExecutor abstract class and overrides the doExecute method. This method uses the LogFactoryUtil to display an INFO message in the console’s logs.