Align dynamic action behaviour with the static ones (#1764)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-07-12 08:30:46 +03:00
committed by GitHub
parent 8e82a9252f
commit 9b9bc7ee00
3 changed files with 69 additions and 51 deletions

View File

@@ -497,6 +497,14 @@ public interface DeploymentManagement {
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
long startScheduledActionsByRolloutGroupParent(long rolloutId, long distributionSetId, Long rolloutGroupParentId); 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<Action> rolloutGroupActions);
/** /**
* Returns {@link DistributionSet} that is assigned to given {@link Target}. * Returns {@link DistributionSet} that is assigned to given {@link Target}.
* *

View File

@@ -13,6 +13,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -711,7 +712,7 @@ public class JpaRolloutExecutor implements RolloutExecutor {
do { do {
// Add up to TRANSACTION_TARGETS actions of the left targets // Add up to TRANSACTION_TARGETS actions of the left targets
// In case a TransactionException is thrown this loop aborts // 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)); Math.min(TRANSACTION_TARGETS, targetsLeftToAdd));
if (createdActions == 0) { if (createdActions == 0) {
break; // no more to assign break; // no more to assign
@@ -781,9 +782,9 @@ public class JpaRolloutExecutor implements RolloutExecutor {
((JpaRolloutManagement) rolloutManagement).publishRolloutGroupCreatedEventAfterCommit(savedGroup, rollout); ((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) { final String targetFilter, final long limit) {
return DeploymentHelper.runInNewTransaction(txManager, "createActionsForRolloutDynamicGroup", status -> { final List<Action> newActions = DeploymentHelper.runInNewTransaction(txManager, "createActionsForRolloutDynamicGroup", status -> {
final PageRequest pageRequest = PageRequest.of(0, Math.toIntExact(limit)); final PageRequest pageRequest = PageRequest.of(0, Math.toIntExact(limit));
final Slice<Target> targets = targetManagement.findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable( final Slice<Target> targets = targetManagement.findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable(
pageRequest, pageRequest,
@@ -791,15 +792,21 @@ public class JpaRolloutExecutor implements RolloutExecutor {
rolloutGroupRepository.findByRolloutOrderByIdAsc(rollout).get(0).getId(), rolloutGroupRepository.findByRolloutOrderByIdAsc(rollout).get(0).getId(),
targetFilter, rollout.getDistributionSet().getType()); targetFilter, rollout.getDistributionSet().getType());
if (targets.getNumberOfElements() > 0) { if (targets.getNumberOfElements() == 0) {
final DistributionSet distributionSet = rollout.getDistributionSet(); return Collections.emptyList();
final ActionType actionType = rollout.getActionType();
final long forceTime = rollout.getForcedTime();
createActions(targets.getContent(), distributionSet, actionType, forceTime, rollout, group);
} }
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 * scheduled actions the scheduled actions gets canceled. A scheduled action
* is created in-active for static and running for dynamic groups. * is created in-active for static and running for dynamic groups.
*/ */
private void createActions(final Collection<Target> targets, final DistributionSet distributionSet, private List<Action> createActions(final Collection<Target> targets, final DistributionSet distributionSet,
final ActionType actionType, final Long forcedTime, final Rollout rollout, final ActionType actionType, final Long forcedTime, final Rollout rollout,
final RolloutGroup rolloutGroup) { final RolloutGroup rolloutGroup) {
// cancel all current scheduled actions for this target. E.g. an action // cancel all current scheduled actions for this target. E.g. an action
@@ -876,22 +883,27 @@ public class JpaRolloutExecutor implements RolloutExecutor {
// created. // created.
final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList()); final List<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toList());
deploymentManagement.cancelInactiveScheduledActionsForTargets(targetIds); deploymentManagement.cancelInactiveScheduledActionsForTargets(targetIds);
targets.forEach(target -> { return targets.stream()
assertActionsPerTargetQuota(target, 1); .map(target -> {
assertActionsPerTargetQuota(target, 1);
final JpaAction action = new JpaAction(); final JpaAction action = new JpaAction();
action.setTarget(target); action.setTarget(target);
action.setActive(rolloutGroup.isDynamic()); action.setActive(false);
action.setDistributionSet(distributionSet); action.setDistributionSet(distributionSet);
action.setActionType(actionType); action.setActionType(actionType);
action.setForcedTime(forcedTime); action.setForcedTime(forcedTime);
action.setStatus(rolloutGroup.isDynamic() ? Status.RUNNING : Status.SCHEDULED); action.setStatus(Status.SCHEDULED);
action.setRollout(rollout); action.setRollout(rollout);
action.setRolloutGroup(rolloutGroup); action.setRolloutGroup(rolloutGroup);
action.setInitiatedBy(rollout.getCreatedBy()); action.setInitiatedBy(rollout.getCreatedBy());
rollout.getWeight().ifPresent(action::setWeight); rollout.getWeight().ifPresent(action::setWeight);
actionRepository.save(action); actionRepository.save(action);
});
return action;
})
.map(Action.class::cast)
.toList();
} }
/** /**

View File

@@ -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.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; 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.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
@@ -645,44 +644,43 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
long totalActionsCount = 0L; long totalActionsCount = 0L;
long lastStartedActionsCount; long lastStartedActionsCount;
do { do {
lastStartedActionsCount = startScheduledActionsByRolloutGroupParentInNewTransaction(rolloutId, lastStartedActionsCount = DeploymentHelper.runInNewTransaction(
distributionSetId, rolloutGroupParentId, ACTION_PAGE_LIMIT); txManager,
"startScheduledActions-" + rolloutId,
status -> {
final Page<Action> 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; totalActionsCount += lastStartedActionsCount;
} while (lastStartedActionsCount > 0); } while (lastStartedActionsCount > 0);
return totalActionsCount; 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<Action> rolloutGroupActions = findActionsByRolloutAndRolloutGroupParent(rolloutId,
rolloutGroupParentId, limit);
if (rolloutGroupActions.getContent().isEmpty()) { @Override
return 0L; public void startScheduledActions(final List<Action> rolloutGroupActions) {
}
final List<Action> newTargetAssignments = handleTargetAssignments(rolloutGroupActions);
if (!newTargetAssignments.isEmpty()) {
onlineDsAssignmentStrategy.sendDeploymentEvents(distributionSetId, newTargetAssignments);
}
return rolloutGroupActions.getTotalElements();
});
}
private List<Action> handleTargetAssignments(final Page<Action> rolloutGroupActions) {
// Close actions already assigned and collect pending assignments // Close actions already assigned and collect pending assignments
final List<JpaAction> pendingTargetAssignments = rolloutGroupActions.getContent().stream() final List<JpaAction> pendingTargetAssignments = rolloutGroupActions.stream()
.map(JpaAction.class::cast).map(this::closeActionIfSetWasAlreadyAssigned).filter(Objects::nonNull) .map(JpaAction.class::cast).map(this::closeActionIfSetWasAlreadyAssigned).filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toList());
if (pendingTargetAssignments.isEmpty()) { if (pendingTargetAssignments.isEmpty()) {
return new ArrayList<>(pendingTargetAssignments); return;
} }
// check if old actions needs to be canceled first // check if old actions needs to be canceled first
return startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments); final List<Action> newTargetAssignments = startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments);
if (!newTargetAssignments.isEmpty()) {
onlineDsAssignmentStrategy.sendDeploymentEvents(newTargetAssignments.get(0).getDistributionSet().getId(), newTargetAssignments);
}
} }
private Page<Action> findActionsByRolloutAndRolloutGroupParent(final Long rolloutId, private Page<Action> findActionsByRolloutAndRolloutGroupParent(final Long rolloutId,