diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java index 3b27434dc..0ead26944 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java @@ -497,6 +497,14 @@ public interface DeploymentManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) long startScheduledActionsByRolloutGroupParent(long rolloutId, long distributionSetId, Long rolloutGroupParentId); + /** + * Handles the target assignments. Shall be part of same group + * + * @param rolloutGroupActions rollouts group actions part of a same group + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + void startScheduledActions(final List rolloutGroupActions); + /** * Returns {@link DistributionSet} that is assigned to given {@link Target}. * diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java index 40416b84e..11896d761 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutExecutor.java @@ -13,6 +13,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -711,7 +712,7 @@ public class JpaRolloutExecutor implements RolloutExecutor { do { // Add up to TRANSACTION_TARGETS actions of the left targets // In case a TransactionException is thrown this loop aborts - final long createdActions = createActionsForDynamicGroupInNewTransaction(rollout, group, groupTargetFilter, + final int createdActions = createActionsForDynamicGroupInNewTransaction(rollout, group, groupTargetFilter, Math.min(TRANSACTION_TARGETS, targetsLeftToAdd)); if (createdActions == 0) { break; // no more to assign @@ -781,9 +782,9 @@ public class JpaRolloutExecutor implements RolloutExecutor { ((JpaRolloutManagement) rolloutManagement).publishRolloutGroupCreatedEventAfterCommit(savedGroup, rollout); } - private Long createActionsForDynamicGroupInNewTransaction(final JpaRollout rollout, final RolloutGroup group, + private int createActionsForDynamicGroupInNewTransaction(final JpaRollout rollout, final RolloutGroup group, final String targetFilter, final long limit) { - return DeploymentHelper.runInNewTransaction(txManager, "createActionsForRolloutDynamicGroup", status -> { + final List newActions = DeploymentHelper.runInNewTransaction(txManager, "createActionsForRolloutDynamicGroup", status -> { final PageRequest pageRequest = PageRequest.of(0, Math.toIntExact(limit)); final Slice targets = targetManagement.findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable( pageRequest, @@ -791,15 +792,21 @@ public class JpaRolloutExecutor implements RolloutExecutor { rolloutGroupRepository.findByRolloutOrderByIdAsc(rollout).get(0).getId(), targetFilter, rollout.getDistributionSet().getType()); - if (targets.getNumberOfElements() > 0) { - final DistributionSet distributionSet = rollout.getDistributionSet(); - final ActionType actionType = rollout.getActionType(); - final long forceTime = rollout.getForcedTime(); - createActions(targets.getContent(), distributionSet, actionType, forceTime, rollout, group); + if (targets.getNumberOfElements() == 0) { + return Collections.emptyList(); } - return Long.valueOf(targets.getNumberOfElements()); + final DistributionSet distributionSet = rollout.getDistributionSet(); + final ActionType actionType = rollout.getActionType(); + final long forceTime = rollout.getForcedTime(); + return createActions(targets.getContent(), distributionSet, actionType, forceTime, rollout, group); }); + + if (!newActions.isEmpty()) { + deploymentManagement.startScheduledActions(newActions); + } + + return newActions.size(); } /** @@ -867,7 +874,7 @@ public class JpaRolloutExecutor implements RolloutExecutor { * scheduled actions the scheduled actions gets canceled. A scheduled action * is created in-active for static and running for dynamic groups. */ - private void createActions(final Collection targets, final DistributionSet distributionSet, + private List createActions(final Collection targets, final DistributionSet distributionSet, final ActionType actionType, final Long forcedTime, final Rollout rollout, final RolloutGroup rolloutGroup) { // cancel all current scheduled actions for this target. E.g. an action @@ -876,22 +883,27 @@ public class JpaRolloutExecutor implements RolloutExecutor { // created. final List targetIds = targets.stream().map(Target::getId).collect(Collectors.toList()); deploymentManagement.cancelInactiveScheduledActionsForTargets(targetIds); - targets.forEach(target -> { - assertActionsPerTargetQuota(target, 1); + return targets.stream() + .map(target -> { + assertActionsPerTargetQuota(target, 1); - final JpaAction action = new JpaAction(); - action.setTarget(target); - action.setActive(rolloutGroup.isDynamic()); - action.setDistributionSet(distributionSet); - action.setActionType(actionType); - action.setForcedTime(forcedTime); - action.setStatus(rolloutGroup.isDynamic() ? Status.RUNNING : Status.SCHEDULED); - action.setRollout(rollout); - action.setRolloutGroup(rolloutGroup); - action.setInitiatedBy(rollout.getCreatedBy()); - rollout.getWeight().ifPresent(action::setWeight); - actionRepository.save(action); - }); + final JpaAction action = new JpaAction(); + action.setTarget(target); + action.setActive(false); + action.setDistributionSet(distributionSet); + action.setActionType(actionType); + action.setForcedTime(forcedTime); + action.setStatus(Status.SCHEDULED); + action.setRollout(rollout); + action.setRolloutGroup(rolloutGroup); + action.setInitiatedBy(rollout.getCreatedBy()); + rollout.getWeight().ifPresent(action::setWeight); + actionRepository.save(action); + + return action; + }) + .map(Action.class::cast) + .toList(); } /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java index a26d28288..7548b9f98 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java @@ -64,7 +64,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; -import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; @@ -645,44 +644,43 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl long totalActionsCount = 0L; long lastStartedActionsCount; do { - lastStartedActionsCount = startScheduledActionsByRolloutGroupParentInNewTransaction(rolloutId, - distributionSetId, rolloutGroupParentId, ACTION_PAGE_LIMIT); + lastStartedActionsCount = DeploymentHelper.runInNewTransaction( + txManager, + "startScheduledActions-" + rolloutId, + status -> { + final Page rolloutGroupActions = findActionsByRolloutAndRolloutGroupParent( + rolloutId, rolloutGroupParentId, ACTION_PAGE_LIMIT); + + if (rolloutGroupActions.getContent().isEmpty()) { + return 0L; + } + + // self invocation won't check @PreAuthorize but it is already checked for the method + startScheduledActions(rolloutGroupActions.getContent()); + + return rolloutGroupActions.getTotalElements(); + }); totalActionsCount += lastStartedActionsCount; } while (lastStartedActionsCount > 0); return totalActionsCount; } - private long startScheduledActionsByRolloutGroupParentInNewTransaction(final Long rolloutId, - final Long distributionSetId, final Long rolloutGroupParentId, final int limit) { - return DeploymentHelper.runInNewTransaction(txManager, "startScheduledActions-" + rolloutId, status -> { - final Page rolloutGroupActions = findActionsByRolloutAndRolloutGroupParent(rolloutId, - rolloutGroupParentId, limit); - if (rolloutGroupActions.getContent().isEmpty()) { - return 0L; - } - - final List newTargetAssignments = handleTargetAssignments(rolloutGroupActions); - - if (!newTargetAssignments.isEmpty()) { - onlineDsAssignmentStrategy.sendDeploymentEvents(distributionSetId, newTargetAssignments); - } - - return rolloutGroupActions.getTotalElements(); - }); - } - - private List handleTargetAssignments(final Page rolloutGroupActions) { + @Override + public void startScheduledActions(final List rolloutGroupActions) { // Close actions already assigned and collect pending assignments - final List pendingTargetAssignments = rolloutGroupActions.getContent().stream() + final List pendingTargetAssignments = rolloutGroupActions.stream() .map(JpaAction.class::cast).map(this::closeActionIfSetWasAlreadyAssigned).filter(Objects::nonNull) .collect(Collectors.toList()); if (pendingTargetAssignments.isEmpty()) { - return new ArrayList<>(pendingTargetAssignments); + return; } // check if old actions needs to be canceled first - return startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments); + final List newTargetAssignments = startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments); + if (!newTargetAssignments.isEmpty()) { + onlineDsAssignmentStrategy.sendDeploymentEvents(newTargetAssignments.get(0).getDistributionSet().getId(), newTargetAssignments); + } } private Page findActionsByRolloutAndRolloutGroupParent(final Long rolloutId,