Async Tasks
Important: This module works only for Ontimize Boot version 3.8.0 or above. Actual release version:
Introduction
The Async Task system will allow you to run decoupled, asynchronous tasks. This module will let you run any service method in a separate, newly created thread, by simply adding an annotation to its controller method.
Previous concepts
- Task: It is the generic representation of a decoupled task. It stores information such as its UUID, its current status and the result of the execution.
- Aspect: It is a modularization of a concern that cuts across multiple classes. It allows us to intercept the execution of any given method or class and implement some alternative or extra behaviour for it.
Prerequisites
You can follow this tutorial using your own application, although for this example we will use an application created using the archetype that can be found on this page and with a REST service.
There are 2 options to follow this tutorial, clone the repository with the initial state and follow the tutorial step by step, or download the final example and see which files are new and which have been updated.
Initial project
/$ git clone https://github.com/ontimize/ontimize-examples
/ontimize-examples$ cd ontimize-examples
/ontimize-examples$ git checkout boot-async-task-initial
Final example
/$ git clone https://github.com/ontimize/ontimize-examples
/ontimize-examples$ cd ontimize-examples
/ontimize-examples$ git checkout boot-async-task
Note: To simplify the code being written, three dots (…) may appear in some parts of the code. This indicates that there may be previous code before and after those dots.
Steps
Database
Tasks Table
With the database started, we create the new table that will store the tasks information.
1
CREATE TABLE TASKS(ID INTEGER IDENTITY NOT NULL PRIMARY KEY, UUID VARCHAR(255) NOT NULL, STATUS VARCHAR(255), RESULT VARBINARY(16777216));
Server
Add Ontimize AsyncTask dependencies
Note: The decoupled tasks system is integrated in the Ontimize Core module, so we need to declare it as a project dependency.
-
ontimize-examples
-
projectwiki-api
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
api
-
core
-
service
- IUserService.java
-
service
-
core
-
api
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
-
projectwiki-boot
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
- ServerApplication.java
-
projectwiki
-
ontimize
-
com
-
resources
- application.yml
-
java
-
main
- pom.xml
-
src
-
projectwiki-model
-
src
-
main
-
db
- templateDB.properties
- templateDB.txt
-
java
-
com
-
ontimize
-
projectwiki
-
model
-
core
-
dao
- UserDao.java
- UserRoleDao.java
-
service
- UserService.java
-
dao
-
core
-
model
-
projectwiki
-
ontimize
-
com
-
resources
-
dao
- placeholders.properties
- RoleDao.xml
- RoleServerPermissionDao.xml
- ServerPermissionDao.xml
- UserDao.xml
- UserRoleDao.xml
-
dao
-
db
-
main
- pom.xml
-
src
-
projectwiki-ws
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
ws
-
core
-
rest
- MainRestController.java
- TestRestController.java
- UserRestController.java
-
rest
-
core
-
ws
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
- .gitignore
- pom.xml
- README.md
-
projectwiki-api
boot/pom.xml
model/pom.xml
Modify application.yml
The application.yml file will be modified to enable the decoupled tasks module, indicate the storage engine it will use, the URL base path for the service, and its thread pool configuration. In this link you have information about the configuration of the asynchronous tasks system in the application.yml file.
Note: The enable property must be set to true and the storage engine type must be specified in the engine property before the server is started.
Important: The asynchronous tasks system requires the Ontimize TaskExecutor to be configured, see this link.
-
ontimize-examples
-
projectwiki-api
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
api
-
core
-
entities
- Candidate.java
-
service
- ICandidateService.java
- IUserService.java
-
entities
-
core
-
api
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
-
projectwiki-boot
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
- ServerApplication.java
-
projectwiki
-
ontimize
-
com
-
resources
- application.yml
-
java
-
main
- pom.xml
-
src
-
projectwiki-model
-
src
-
main
-
db
- templateDB.properties
- templateDB.txt
-
java
-
com
-
ontimize
-
projectwiki
-
model
-
core
-
dao
- CandidateDao.java
- TaskDao.java
- UserDao.java
- UserRoleDao.java
-
service
- CandidateService.java
- UserService.java
-
dao
-
core
-
model
-
projectwiki
-
ontimize
-
com
-
resources
-
dao
- CandidateDao.xml
- placeholders.properties
- RoleDao.xml
- RoleServerPermissionDao.xml
- ServerPermissionDao.xml
- TaskDao.xml
- UserDao.xml
- UserRoleDao.xml
-
dao
-
db
-
main
- pom.xml
-
src
-
projectwiki-ws
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
ws
-
core
-
rest
- CandidateRestController.java
- MainRestController.java
- TestRestController.java
- UserRestController.java
-
rest
-
core
-
ws
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
- .gitignore
- pom.xml
- README.md
-
projectwiki-api
application.yml
For database storage
Add Task DAO
A specific DAO will be created for the tasks table, and it will implement the DAO interface in the tasks module.
-
ontimize-examples
-
projectwiki-api
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
api
-
core
-
service
- IUserService.java
-
service
-
core
-
api
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
-
projectwiki-boot
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
- ServerApplication.java
-
projectwiki
-
ontimize
-
com
-
resources
- application.yml
-
java
-
main
- pom.xml
-
src
-
projectwiki-model
-
src
-
main
-
db
- templateDB.properties
- templateDB.txt
-
java
-
com
-
ontimize
-
projectwiki
-
model
-
core
-
dao
- TaskDao.java
- UserDao.java
- UserRoleDao.java
-
service
- UserService.java
-
dao
-
core
-
model
-
projectwiki
-
ontimize
-
com
-
resources
-
dao
- placeholders.properties
- RoleDao.xml
- RoleServerPermissionDao.xml
- ServerPermissionDao.xml
- TaskDao.xml
- UserDao.xml
- UserRoleDao.xml
-
dao
-
db
-
main
- pom.xml
-
src
-
projectwiki-ws
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
ws
-
core
-
rest
- MainRestController.java
- TestRestController.java
- UserRestController.java
-
rest
-
core
-
ws
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
- .gitignore
- pom.xml
- README.md
-
projectwiki-api
TaskDao.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<JdbcEntitySetup xmlns="http://www.ontimize.com/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.ontimize.com/schema/jdbc http://www.ontimize.com/schema/jdbc/ontimize-jdbc-dao.xsd"
table="TASKS" datasource="mainDataSource" sqlhandler="dbSQLStatementHandler">
<DeleteKeys>
<Column>ID</Column>
</DeleteKeys>
<UpdateKeys>
<Column>ID</Column>
</UpdateKeys>
<GeneratedKey>ID</GeneratedKey>
</JdbcEntitySetup>
TaskDao.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.imatia.qsallcomponents.model.dao;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import com.ontimize.boot.core.asynctask.IAsyncTaskDao;
import com.ontimize.jee.server.dao.common.ConfigurationFile;
import com.ontimize.jee.server.dao.jdbc.OntimizeJdbcDaoSupport;
@Lazy
@Repository(value = "TaskDao")
@ConfigurationFile(configurationFile = "dao/TaskDao.xml", configurationFilePlaceholder = "dao/placeholders.properties")
public class TaskDao extends OntimizeJdbcDaoSupport implements IAsyncTaskDao {
public static final String ATTR_ID = "ID";
public static final String ATTR_UUID = "UUID";
public static final String ATTR_STATUS = "STATUS";
public static final String ATTR_RESULT = "RESULT";
public TaskDao() {
super();
}
}
Annotate controller method
In order to run some service method asynchronously, we need to annotate its respective REST controller method with @OAsyncTask. This way, a new thread will be created in order to handle the method’s execution, and we will recieve an instant response with the URL where we can check the execution status and retrieve its result when it’s finished.
Important: The service’s method MUST return a serializable object with getters and setters, as well as the controller’s method must return a ResponseEntity object. In this case, the query()
method returns a Serializable object, the EntityResult.
-
ontimize-examples
-
projectwiki-api
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
api
-
core
-
service
- ICandidateService.java
- IUserService.java
-
service
-
core
-
api
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
-
projectwiki-boot
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
- ServerApplication.java
-
projectwiki
-
ontimize
-
com
-
resources
- application.yml
-
java
-
main
- pom.xml
-
src
-
projectwiki-model
-
src
-
main
-
db
- templateDB.properties
- templateDB.txt
-
java
-
com
-
ontimize
-
projectwiki
-
model
-
core
-
dao
- CandidateDao.java
- TaskDao.java
- UserDao.java
- UserRoleDao.java
-
service
- CandidateService.java
- UserService.java
-
dao
-
core
-
model
-
projectwiki
-
ontimize
-
com
-
resources
-
dao
- CandidateDao.xml
- placeholders.properties
- RoleDao.xml
- RoleServerPermissionDao.xml
- ServerPermissionDao.xml
- TaskDao.xml
- UserDao.xml
- UserRoleDao.xml
-
dao
-
db
-
main
- pom.xml
-
src
-
projectwiki-ws
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
ws
-
core
-
rest
- CandidateRestController.java
- MainRestController.java
- TestRestController.java
- UserRestController.java
-
rest
-
core
-
ws
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
- .gitignore
- pom.xml
- README.md
-
projectwiki-api
We will override the query()
method of the ORestController class.
CandidateRestController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.ontimize.projectwiki.ws.core.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ontimize.boot.core.asynctask.OAsyncTask;
import com.ontimize.jee.common.dto.EntityResult;
import com.ontimize.jee.server.rest.ORestController;
import com.ontimize.projectwiki.api.core.service.ICandidateService;
@RestController
@RequestMapping("/candidates")
@ComponentScan(basePackageClasses = { com.ontimize.projectwiki.api.core.service.ICandidateService.class })
public class CandidateRestController extends ORestController<ICandidateService>{
@Autowired
private ICandidateService candidateService;
@Override
public ICandidateService getService() {
return this.candidateService;
}
@OAsyncTask
@Override
public ResponseEntity<EntityResult> query(@PathVariable("name") String name,
@RequestParam(name = "filter", required = false) String filter,
@RequestParam(name = "columns", required = false) String columns) {
return super.query(name, filter, columns);
}
}
Delay service method
To know all the states through which the asynchronous request passes, we will add a delay in the candidateQuery()
method.
-
ontimize-examples
-
projectwiki-api
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
api
-
core
-
service
- ICandidateService.java
- IUserService.java
-
service
-
core
-
api
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
-
projectwiki-boot
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
- ServerApplication.java
-
projectwiki
-
ontimize
-
com
-
resources
- application.yml
-
java
-
main
- pom.xml
-
src
-
projectwiki-model
-
src
-
main
-
db
- templateDB.properties
- templateDB.txt
-
java
-
com
-
ontimize
-
projectwiki
-
model
-
core
-
dao
- CandidateDao.java
- TaskDao.java
- UserDao.java
- UserRoleDao.java
-
service
- CandidateService.java
- UserService.java
-
dao
-
core
-
model
-
projectwiki
-
ontimize
-
com
-
resources
-
dao
- CandidateDao.xml
- placeholders.properties
- RoleDao.xml
- RoleServerPermissionDao.xml
- ServerPermissionDao.xml
- TaskDao.xml
- UserDao.xml
- UserRoleDao.xml
-
dao
-
db
-
main
- pom.xml
-
src
-
projectwiki-ws
-
src
-
main
-
java
-
com
-
ontimize
-
projectwiki
-
ws
-
core
-
rest
- CandidateRestController.java
- MainRestController.java
- TestRestController.java
- UserRestController.java
-
rest
-
core
-
ws
-
projectwiki
-
ontimize
-
com
-
java
-
main
- pom.xml
-
src
- .gitignore
- pom.xml
- README.md
-
projectwiki-api
CandidateService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.ontimize.projectwiki.model.core.service;
import java.util.concurrent.TimeUnit;
. . .
@Service("CandidateService")
@Lazy
public class CandidateService implements ICandidateService {
. . .
@Override
public EntityResult candidateQuery(Map<String, Object> keyMap, List<String> attrList)
throws OntimizeJEERuntimeException {
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.daoHelper.query(this.candidateDao, keyMap, attrList);
}
. . .
}
Testing
To test the asynchronous tasks we need to execute a REST request to the method that we have marked with the annotation @OAsyncTask.
In this case, the request is GET and has the following structure: http://localhost:33333/candidates/candidate?columns=ID,NAME,SURNAME
Element | Meaning |
---|---|
localhost:33333 | Indicates the host |
/candidates | Indicates the service to be queried |
/candidate | Indicates the DAO that will access that service |
?columns= | Indicates the columns to be queried |
The authorization used for this requests is authorization of the type BASIC.
The access must be done with a user and password example:
User: demo
Password: demouser
When you run the query, it should return a 202 Accepted with the following header: Location.
This header contains the relative path to the asynchronous task that you have to execute to receive the data.
Example: Location:
/tasks/f16e9af7-ec0f-444c-a173-5b0179f5d57f
To execute the query the request needs to be GET and have the following structure: http://localhost:33333/tasks/f16e9af7-ec0f-444c-a173-5b0179f5d57f
Note: The uuid that goes after /tasks
varies in each execution of the previous query.
The first time you run this query the status becomes Started. When the time set in the delay expires the second time you execute the query, the status becomes Completed, returns the request data and removes the task from the TASKS table.