Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a2dfcc2
HDPI-6585: add camunda api, task creation and dmns
gmmagruder Jul 16, 2026
ae67522
HDPI-6585: add configuration dmn
gmmagruder Jul 16, 2026
fe7c854
HDPI-6585: add unit test to camunda service
gmmagruder Jul 16, 2026
d4f6968
HDPI-6585: add feature flag and camunda url
gmmagruder Jul 16, 2026
b0d233c
HDPI-6585: add access for WA user
gmmagruder Jul 16, 2026
57ca7ab
Merge branch 'HDPI-wa-preview-chart' into HDPI-6585-new-claim-create-…
scottstewart-sl Jul 20, 2026
8e6c889
Merge branch 'HDPI-wa-preview-chart' into HDPI-6585-new-claim-create-…
scottstewart-sl Jul 20, 2026
5d801f2
Merge branch 'master' into HDPI-6585-new-claim-create-new-hearing
gmmagruder Jul 21, 2026
98810ba
HDPI-6585: add feature flag to CamundaService
gmmagruder Jul 21, 2026
96cb778
HDPI-6501: fix checkstyle
gmmagruder Jul 21, 2026
853b1c7
HDPI-6501: add task creation to notify case issued event
gmmagruder Jul 21, 2026
1aed3cd
HDPI-6501: add role assignment url
gmmagruder Jul 21, 2026
e23dda0
HDPI-6501: add publish to camunda and add role assignment url to wa-t…
gmmagruder Jul 22, 2026
6bf7728
HDPI-6585: add service bus to ccd preview
gmmagruder Jul 22, 2026
471dc33
HDPI-6585: update cron job config
gmmagruder Jul 22, 2026
d6786ba
HDPI-6585: reverse changes
gmmagruder Jul 22, 2026
576668a
HDPI-6585: stop suspension of cron jobs
gmmagruder Jul 22, 2026
222c443
HDPI-6585: add WA access to more states
gmmagruder Jul 22, 2026
716b22a
HDPI-6585: add WA access to more states
gmmagruder Jul 22, 2026
f95cde5
HDPI-6585: remove WA access to property address
gmmagruder Jul 22, 2026
5b486c2
HDPI-6585: increase WA access to fields in PCS case
gmmagruder Jul 22, 2026
323e326
HDPI-6585: add WA access to AWAITING_SUBMISSION_TO_HMCTS
gmmagruder Jul 22, 2026
82a4575
HDPI-6585: increase WA access
gmmagruder Jul 22, 2026
dd8a2fa
HDPI-6585: specify camunda version to fix bpm upload problem
gmmagruder Jul 23, 2026
ddce3bc
HDPI-6585: reverse change to image version
gmmagruder Jul 23, 2026
cb056d4
HDPI-6585: change to a different camunda version
gmmagruder Jul 23, 2026
f583ebf
HDPI-6585: add caseworker access profile
gmmagruder Jul 23, 2026
0d811e6
HDPI-6585: fix merge conflicts
gmmagruder Jul 23, 2026
e0e2ff0
HDPI-6585: add interval days and move service bus config to applicati…
gmmagruder Jul 23, 2026
f5392be
HDPI-6585: add definition-snapshots to dockerfile
gmmagruder Jul 23, 2026
d6dcd28
HDPI-6585: add depend on dumpCCDDefinitions
gmmagruder Jul 23, 2026
ea78b96
HDPI-6585: reverse changes to Dockerfile
gmmagruder Jul 23, 2026
a4093c3
HDPI-6585: programmatically send cancel task message
gmmagruder Jul 24, 2026
7f7fc6a
HDPI-6585: fix unit test
gmmagruder Jul 24, 2026
89d4b27
HDPI-6585: use task id for process categories and add unit test
gmmagruder Jul 24, 2026
ce6fde9
HDPI-6585: update dmns and remove service bus config
gmmagruder Jul 24, 2026
701a2d0
HDPI-6585: update dmn id
gmmagruder Jul 24, 2026
88dda10
HDPI-6585: Schedule Camunda task creation via db-scheduler (#2258)
scottstewart-sl Jul 24, 2026
7c847de
HDPI-6585: remove feature flag show condition and add CAMUNDA_BASE_UR…
gmmagruder Jul 24, 2026
75ef882
HDPI-6585: disableActiveClusterCheck and set suspend to false
gmmagruder Jul 24, 2026
bed6271
HDPI-6585: reverse change to dmn
gmmagruder Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/pcs-api/values.ccd.preview.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ xui-webapp:
nodejs:
imagePullPolicy: Always
releaseNameOverride: ${SERVICE_NAME}-xui-webapp
image: hmctsprod.azurecr.io/xui/webapp:latest
image: hmctsprod.azurecr.io/xui/webapp:pr-5239

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

To be reversed

ingressHost: xui-${SERVICE_FQDN}
devmemoryRequests: 2Gi
devcpuRequests: 500m
Expand Down
36 changes: 9 additions & 27 deletions charts/pcs-api/values.wa.preview.template.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,6 @@
java:
secrets:
AZURE_SERVICE_BUS_CONNECTION_STRING:
secretRef: pcs-sb-preview
key: connectionString
AZURE_SERVICE_BUS_PREVIEW_CONNECTION_STRING:
secretRef: pcs-sb-preview
key: connectionString
environment:
SPRING_JMS_SERVICEBUS_ENABLED: true
AZURE_SERVICE_BUS_TOPIC_NAME: ${SERVICE_NAME}-asb-ccd-case-events
AZURE_SERVICE_BUS_SUBSCRIPTION_NAME: ${SERVICE_NAME}-asb-ccd-case-events

servicebus:
enabled: true
releaseNameOverride: ${SERVICE_NAME}-asb
resourceGroup: pcs-aso-preview-rg
sbNamespace: pcs-servicebus-preview
setup:
topics:
- name: crd-topic
subscriptionNeeded: yes
- name: jrd-topic
subscriptionNeeded: yes
- name: ccd-case-events
subscriptionNeeded: yes
requiresSession: true
CAMUNDA_BASE_URL: http://pcs-api-pr-${CHANGE_ID}-camunda/engine-rest
Comment thread
scottstewart-sl marked this conversation as resolved.

postgresql:
enabled: true
Expand Down Expand Up @@ -52,7 +28,7 @@ wa:

camunda-bpm:
java:
image: hmctsprod.azurecr.io/camunda/bpm:latest
image: hmctsprod.azurecr.io/camunda/bpm:pr-1025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

To be reversed


wa-case-event-handler:
java:
Expand All @@ -64,6 +40,7 @@ wa:
AZURE_SERVICE_BUS_TOPIC_NAME: ${SERVICE_NAME}-asb-ccd-case-events
AZURE_SERVICE_BUS_SUBSCRIPTION_NAME: ${SERVICE_NAME}-asb-ccd-case-events
AZURE_SERVICE_BUS_CCD_CASE_EVENTS_SUBSCRIPTION_NAME: ${SERVICE_NAME}-asb-ccd-case-events
ROLE_ASSIGNMENT_URL: http://am-role-assignment-service-aat.service.core-compute-aat.internal
keyVaults:
wa:
secrets:
Expand All @@ -80,8 +57,9 @@ wa:
java:
ingressHost: wa-task-management-api-${SERVICE_FQDN}
environment:
ALLOWED_CASE_TYPES: pcs-${CHANGE_ID}
ALLOWED_CASE_TYPES: pcs
ALLOWED_JURISDICTIONS: pcs
ROLE_ASSIGNMENT_URL: http://am-role-assignment-service-aat.service.core-compute-aat.internal
keyVaults:
wa:
secrets:
Expand Down Expand Up @@ -136,6 +114,8 @@ wa:
wa-initiation-batch:
job:
schedule: "*/1 * * * *"
disableActiveClusterCheck: true
suspend: false

wa-reconfiguration-batch:
job:
Expand All @@ -144,6 +124,8 @@ wa:
wa-termination-batch:
job:
schedule: "*/1 * * * *"
disableActiveClusterCheck: true
suspend: false

#disable wa db as we are using the postgres flexible server
wa:
Expand Down
1 change: 1 addition & 0 deletions charts/pcs-api/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ java:
CCD_DATA_STORE_URL: "http://ccd-data-store-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal"
CASE_DOCUMENT_AM_URL: "http://ccd-case-document-am-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal"
RD_PROFESSIONAL_API_URL: "http://rd-professional-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal"
CAMUNDA_BASE_URL: "http://camunda-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal"
servicebus:
enabled: false
ccd:
Expand Down
3 changes: 2 additions & 1 deletion featureFlags/flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"bulk-print-enabled": false,
"caseworker-events-enabled": true,
"cui-respond-to-claim-lr-enabled": true,
"release-1.2-enabled": true
"release-1.2-enabled": true,
"caseworker-wa-enabled": false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ private void createAccessProfiles(CFTLib lib) {
roleNames.add("caseworker");
roleNames.add("caseworker-ras-validation");
roleNames.add("GS_profile");
roleNames.add("caseworker-wa-task-configuration");

lib.createRoles(roleNames.toArray(new String[0]));
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/uk/gov/hmcts/reform/pcs/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import uk.gov.hmcts.reform.ccd.document.am.feign.CaseDocumentClientApi;
import uk.gov.hmcts.reform.fees.client.FeesApi;
import uk.gov.hmcts.reform.idam.client.IdamApi;
import uk.gov.hmcts.reform.pcs.camunda.CamundaApi;
import uk.gov.hmcts.reform.pcs.hearings.service.api.HmcHearingApi;
import uk.gov.hmcts.reform.pcs.idam.IdamUserInfoApi;
import uk.gov.hmcts.reform.pcs.location.service.api.LocationReferenceApi;
Expand All @@ -31,7 +32,8 @@

RdProfessionalApi.class,
FeesApi.class,
CaseDocumentClientApi.class
CaseDocumentClientApi.class,
CamundaApi.class
}
)

Expand Down
19 changes: 19 additions & 0 deletions src/main/java/uk/gov/hmcts/reform/pcs/camunda/CamundaApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package uk.gov.hmcts.reform.pcs.camunda;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;

@FeignClient(name = "camunda", url = "${camunda.url}")
public interface CamundaApi {
String SERVICE_AUTHORIZATION = "ServiceAuthorization";

@PostMapping(
value = "/message",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
void sendMessage(@RequestHeader(SERVICE_AUTHORIZATION) String serviceAuthorisation,
SendMessageRequest sendMessageRequest);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package uk.gov.hmcts.reform.pcs.camunda;

import com.github.kagkarlsson.scheduler.task.CompletionHandler;
import com.github.kagkarlsson.scheduler.task.FailureHandler;
import com.github.kagkarlsson.scheduler.task.TaskDescriptor;
import com.github.kagkarlsson.scheduler.task.helper.CustomTask;
import com.github.kagkarlsson.scheduler.task.helper.Tasks;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.time.Duration;

@Slf4j
@Component
public class CamundaRequestTaskComponent {

private static final String CAMUNDA_REQUEST_TASK_NAME = "camunda-request-task";

public static final TaskDescriptor<CamundaRequestTaskData> CAMUNDA_REQUEST_TASK_DESCRIPTOR =
TaskDescriptor.of(CAMUNDA_REQUEST_TASK_NAME, CamundaRequestTaskData.class);

private final CamundaService camundaService;
private final int maxRetries;
private final Duration backoffDelay;

public CamundaRequestTaskComponent(CamundaService camundaService,
@Value("${camunda.request.max-retries}") int maxRetries,
@Value("${camunda.request.backoff-delay-duration}") Duration backoffDelay) {

this.camundaService = camundaService;
this.maxRetries = maxRetries;
this.backoffDelay = backoffDelay;
}

@Bean
public CustomTask<CamundaRequestTaskData> camundaRequestTask() {
return Tasks.custom(CAMUNDA_REQUEST_TASK_DESCRIPTOR)
.onFailure(
FailureHandler.<CamundaRequestTaskData>maxRetries(maxRetries)
.withBackoff(backoffDelay)
.thenRemove(complete ->
log.warn(
"Execution has failed {} times. Giving up.",
complete.getExecution().consecutiveFailures
)
))
.execute((taskInstance, executionContext) -> {
CamundaRequestTaskData taskData = taskInstance.getData();
log.debug("Executing Camunda request task for {}", taskData);
try {
camundaService.handleRequest(taskData);
return new CompletionHandler.OnCompleteRemove<>();
} catch (Exception e) {
log.error("Failed to create Camunda request for: {}. Attempt {}/{}",
taskData, executionContext.getExecution().consecutiveFailures + 1, maxRetries, e);
throw e;
}
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package uk.gov.hmcts.reform.pcs.camunda;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
@AllArgsConstructor
public class CamundaRequestTaskData {

enum Action {
CREATE,
CANCEL
}

private final Action action;

private final long caseReference;

private final TaskType taskType;

}
152 changes: 152 additions & 0 deletions src/main/java/uk/gov/hmcts/reform/pcs/camunda/CamundaService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package uk.gov.hmcts.reform.pcs.camunda;

import com.github.kagkarlsson.scheduler.SchedulerClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.reform.authorisation.generators.AuthTokenGenerator;
import uk.gov.hmcts.reform.pcs.camunda.CamundaRequestTaskData.Action;
import uk.gov.hmcts.reform.pcs.ccd.CaseType;
import uk.gov.hmcts.reform.pcs.service.FeatureFlag;
import uk.gov.hmcts.reform.pcs.service.FeatureToggleService;

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
import static uk.gov.hmcts.reform.pcs.camunda.CamundaRequestTaskComponent.CAMUNDA_REQUEST_TASK_DESCRIPTOR;

@Slf4j
@AllArgsConstructor
@Service
public class CamundaService {

private final CamundaApi camundaApi;
private final AuthTokenGenerator authTokenGenerator;
private final SchedulerClient schedulerClient;
private final FeatureToggleService featureToggleService;

private static final String CREATE = "createTaskMessage";
private static final String CANCEL = "cancelTasks";
private static final String UNCONFIGURED = "unconfigured";
private static final String EMPTY_WARNINGS_LIST = "[]";
private static final String CANCELLATION_PROCESS = "CASE_EVENT_CANCELLATION";
private final Clock utcClock;

public void createTask(long caseId, TaskType taskType) {
scheduleCamundaRequest(Action.CREATE, caseId, taskType);
}

public void cancelTask(long caseId, TaskType taskType) {
scheduleCamundaRequest(Action.CANCEL, caseId, taskType);
}

void handleRequest(CamundaRequestTaskData taskData) {
switch (taskData.getAction()) {
case CREATE -> requestTaskCreation(taskData.getCaseReference(), taskData.getTaskType());
case CANCEL -> requestTaskCancellation(taskData.getCaseReference(), taskData.getTaskType());
}
}

private void scheduleCamundaRequest(Action action, long caseId, TaskType taskType) {
if (!featureToggleService.isEnabled(FeatureFlag.CASEWORKER_WA)) {
log.info("Skipped scheduling Camunda request for {}", caseId);
return;
}

CamundaRequestTaskData taskData = CamundaRequestTaskData.builder()
.action(action)
.caseReference(caseId)
.taskType(taskType)
.build();

schedulerClient.scheduleIfNotExists(
CAMUNDA_REQUEST_TASK_DESCRIPTOR
.instance(UUID.randomUUID().toString())
.data(taskData)
.scheduledTo(Instant.now(utcClock)));
}

private void requestTaskCreation(Long caseId, TaskType taskType) {
if (!featureToggleService.isEnabled(FeatureFlag.CASEWORKER_WA)) {
log.info("Skipped creating task for {}", caseId);
return;
}

log.info("Creating task for {}", caseId);
Map<String, DmnValue<?>> processVariables = new ConcurrentHashMap<>();

LocalDateTime delayUntil = LocalDateTime.now(utcClock);
LocalDateTime dueDate = delayUntil.plusDays(taskType.getWorkingDays());

processVariables.put("taskState", dmnStringValue(UNCONFIGURED));
processVariables.put("caseTypeId", dmnStringValue(CaseType.getCaseType()));
processVariables.put("dueDate", dmnStringValue(dueDate.format(ISO_LOCAL_DATE_TIME)));
processVariables.put("workingDaysAllowed", dmnIntegerValue(taskType.getWorkingDays()));
processVariables.put("jurisdiction", dmnStringValue(CaseType.getJurisdictionId()));
processVariables.put("name", dmnStringValue(taskType.getName()));
processVariables.put("taskId", dmnStringValue(taskType.getId()));
processVariables.put("caseId", dmnStringValue(caseId.toString()));
processVariables.put("delayUntil", dmnStringValue(delayUntil.format(ISO_LOCAL_DATE_TIME)));
processVariables.put("hasWarnings", dmnBooleanValue(false));
processVariables.put("warningList", dmnStringValue(EMPTY_WARNINGS_LIST));
processVariables.put("__processCategory__" + taskType.getId(), dmnBooleanValue(true));

SendMessageRequest request = SendMessageRequest.builder()
.messageName(CREATE)
.processVariables(processVariables)
.build();

sendCamundaRequest(request, caseId);
}

private void requestTaskCancellation(Long caseId, TaskType taskType) {
if (!featureToggleService.isEnabled(FeatureFlag.CASEWORKER_WA)) {
log.info("Skipped cancelling task for {}", caseId);
return;
}

Map<String, DmnValue<?>> correlationKeys = new ConcurrentHashMap<>();
correlationKeys.put("caseId", dmnStringValue(caseId.toString()));
correlationKeys.put("__processCategory__" + taskType.getId(), dmnBooleanValue(true));

Map<String, DmnValue<?>> processVariables = new ConcurrentHashMap<>();
processVariables.put("cancellationProcess", dmnStringValue(CANCELLATION_PROCESS));

SendMessageRequest request = SendMessageRequest.builder()
.messageName(CANCEL)
.processVariables(processVariables)
.correlationKeys(correlationKeys)
.build();

sendCamundaRequest(request, caseId);
}

private void sendCamundaRequest(SendMessageRequest request, long caseId) {
String s2sToken = authTokenGenerator.generate();

try {
log.info("Camunda request for case id {}: {}", caseId, request);
camundaApi.sendMessage(s2sToken, request);
} catch (Exception e) {
log.error("Failed to send Camunda request for caseId {}", caseId, e);
}
}

private DmnValue<String> dmnStringValue(String value) {
return DmnValue.<String>builder().value(value).type("String").build();
}

private DmnValue<Integer> dmnIntegerValue(Integer value) {
return DmnValue.<Integer>builder().value(value).type("Integer").build();
}

private DmnValue<Boolean> dmnBooleanValue(Boolean value) {
return DmnValue.<Boolean>builder().value(value).type("Boolean").build();
}

}
Loading