Skip to content

Conversation

@aonych
Copy link
Contributor

@aonych aonych commented Dec 4, 2025

No description provided.

@aonych aonych added the preview label Dec 4, 2025
@alfresco-build alfresco-build added this to the Validating milestone Dec 4, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request changes the relationship between IntegrationContextEntity and ServiceTaskEntity from a one-to-one to a one-to-many relationship, allowing multiple integration contexts to be associated with a single service task. This supports cyclical service tasks and retry scenarios.

Key changes:

  • Changed JPA relationship from @OneToOne to @OneToMany on ServiceTaskEntity and @ManyToOne on IntegrationContextEntity
  • Modified database unique constraint to allow multiple integration contexts per service task
  • Added new REST endpoint /admin/v1/service-tasks/{serviceTaskId}/integration-contexts to retrieve all integration contexts for a service task
  • Added integrationContextCounter field to CloudServiceTask to track the number of integration contexts

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
IntegrationContextEntity.java Changed relationship from @OnetoOne to @manytoone with composite foreign key join columns; removed unique constraint on process/client/execution combination; simplified setServiceTask method
ServiceTaskEntity.java Changed relationship from @OnetoOne to @onetomany; added getIntegrationContextCounter method that counts associated integration contexts
IntegrationContextRepository.java Updated findByProcessInstanceIdAndClientIdAndExecutionId to return Page instead of single entity and added Pageable parameter
ServiceTaskIntegrationContextAdminController.java Refactored findById to findByServiceTaskId with string parsing logic; added new findAllByServiceTaskId endpoint; removed EntityFinder dependency
IntegrationContextRepresentationModelAssembler.java Updated to call renamed controller method findByServiceTaskId
QueryRestControllersAutoConfiguration.java Removed unused import TaskControllerAdvice
IntegrationRequestedEventHandler.java Separated integration context ID from service task ID; now uses integrationContext.getId() directly
IntegrationErrorReceivedEventHandler.java Added explicit service task ID construction using IdBuilderHelper
BaseIntegrationEventHandler.java Changed to use integrationContext.getId() instead of IdBuilderHelper for finding integration contexts
CloudServiceTask.java Added getIntegrationContextCounter() method to interface
CloudServiceTaskImpl.java Implemented integrationContextCounter field with getter, setter, and updated toString method
33-alter.pg.schema.8.8.0.sql Database migration script for PostgreSQL to modify unique constraint
33-alter.oracle.schema.8.8.0.sql Database migration script for Oracle to modify unique constraint
h2.schema.sql Removed unique constraint creation from H2 schema
master.xml Added new Liquibase changesets for database migrations
swagger-expected.json Updated OpenAPI specification with new endpoint, parameters, and schemas; renamed operation from findById to findByServiceTaskId
QueryAdminProcessServiceTasksIT.java Added integration tests for multiple integration contexts functionality
ProcessQueryAdminSteps.java Added step method to retrieve all integration contexts
ProcessQueryAdminService.java Added service method to call new REST endpoint
process-instance-service-tasks-actions.story Added acceptance test scenario for retrieving all integration contexts
ProcessInstanceServiceTasks.java Implemented test steps for verifying multiple integration contexts retrieval

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

# Conflicts:
#	activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-liquibase/src/main/resources/config/query/liquibase/changelog/33-alter.oracle.schema.8.8.0.sql
#	activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-liquibase/src/main/resources/config/query/liquibase/changelog/33-alter.pg.schema.8.8.0.sql
@CLAassistant
Copy link

CLAassistant commented Jan 12, 2026

CLA assistant check
All committers have signed the CLA.

@aonych aonych requested a review from dsibilio January 14, 2026 12:44
Copy link
Member

@erdemedeiros erdemedeiros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! I've added some questions and suggestions

.untilAsserted(() -> {
PagedModel<CloudServiceTask> tasks = processQueryAdminSteps.getServiceTasks(processId);

assertThat(tasks.getContent()).isNotEmpty().hasSize(1).as("Should have exactly one service task");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling isNotEmpty() is redundant. This assertion will already fail if size is different from 1.

.untilAsserted(() -> {
PagedModel<CloudServiceTask> tasks = processQueryAdminSteps.getServiceTasks(processId);

assertThat(tasks.getContent()).isNotEmpty().hasSize(1).as("Should have exactly one service task");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isNotEmpty() is redundant

CloudServiceTask serviceTask = tasks.getContent().iterator().next();

assertThat(serviceTask.getIntegrationContextCounter())
.isNotNull()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isNotNull() is redundant

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nice to add coverage for multi-instances as well once https://hyland.atlassian.net/browse/AAE-41417 is fixed (in a follow up PR).

name = "integration_context_processInstance_elementId_idx",
columnList = "processInstanceId,clientId,executionId",
unique = true
name = "integration_context_proc_client_exec_idx",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth testing how an existing integration context will behave during migration. I think you can test this by making a connector fail in the first attempt, then using replay after migration

public EntityModel<CloudIntegrationContext> toModel(IntegrationContextEntity entity) {
Link selfRel = linkTo(methodOn(ServiceTaskIntegrationContextAdminController.class).findById(entity.getId()))
Link selfRel = linkTo(
methodOn(ServiceTaskIntegrationContextAdminController.class).findByServiceTaskId(entity.getId())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about this? entity here is IntegrationContextEntity, so getId() will be returning the new id format, if you want to use service task Id you need to build it again using IdBuilderHelper.from(entity) as suggested by Copilot. However, this is not going to be selfRel, as it's not retuning the element itself. So I think either we remove the selfRel link here or we expose a new endpoint to be able to return a single IntegrationContext based on its id (/integration-contexts/{inegrationContextID}) and use this new end point for self link

repository,
serviceTaskId,
"Unable to find integration context entity for the given id:'" + serviceTaskId + "'"
public EntityModel<CloudIntegrationContext> findByServiceTaskId(@PathVariable String serviceTaskId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we deprecated this endpoint?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should deprecate this endpoint.

assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isNotNull();
assertThat(responseEntity.getBody().getContent())
.hasSize(1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get ride of .hasSize(1) if you use containsExactly instead of contains

);
assertThat(cloudIntegrationContext)
.isNotEmpty()
.hasSize(2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasSize is redundant. The assertion is already fail if it has a different size because containsExactly is used

);
assertThat(cloudIntegrationContext)
.isNotEmpty()
.hasSize(2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasSize is redundant

Copy link
Member

@erdemedeiros erdemedeiros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@aonych aonych enabled auto-merge (squash) January 19, 2026 13:55
@aonych aonych disabled auto-merge January 19, 2026 16:03
@aonych aonych enabled auto-merge (squash) January 19, 2026 16:03
Copy link
Contributor

@igdianov igdianov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should update

to include IntegrationContextEntity in the optimization logic after service tasks before entityManager.load to avoid performance bottlenecks.

private List<IntegrationContextEntity> integrationContexts;

@Formula(
"(SELECT COUNT(*) FROM INTEGRATION_CONTEXT ic WHERE ic.process_instance_id = process_instance_id AND ic.client_id = element_id AND ic.execution_id = execution_id)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using @Forumula here will cause a performance bottleneck, i.e. N+1 query for each row. This would be solved by incrementing and storing this counter in the completed integration context Query handler.

repository,
serviceTaskId,
"Unable to find integration context entity for the given id:'" + serviceTaskId + "'"
public EntityModel<CloudIntegrationContext> findByServiceTaskId(@PathVariable String serviceTaskId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should deprecate this endpoint.

@@ -0,0 +1,8 @@
ALTER TABLE integration_context
DROP CONSTRAINT integration_context_bpmn_activity_idx;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are going to be running service tasks during the database upgrade window that should be migrated before creating the new index.

@aonych aonych disabled auto-merge January 20, 2026 07:14
@aonych aonych requested a review from igdianov January 20, 2026 17:47
Copy link
Contributor

@igdianov igdianov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job!

@aonych aonych enabled auto-merge (squash) January 20, 2026 19:49
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
51.1% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@aonych aonych merged commit 495ca77 into develop Jan 20, 2026
18 of 19 checks passed
@aonych aonych deleted the feature/AAE-39413-service-task-in-loops branch January 20, 2026 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants