diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java index 302156ac5..590e52a3b 100644 --- a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java @@ -189,6 +189,16 @@ public class ConfigurableScenario { .successThreshold(String.valueOf(scenario.getRolloutSuccessThreshold())).errorThreshold("5").build()) .getBody(); + do { + try { + TimeUnit.SECONDS.sleep(5); + } catch (final InterruptedException e) { + LOGGER.warn("Interrupted!"); + Thread.currentThread().interrupt(); + } + } while (!"READY".equalsIgnoreCase( + rolloutResource.getRollout(rolloutResponseBody.getRolloutId()).getBody().getStatus())); + // start the created Rollout rolloutResource.start(rolloutResponseBody.getRolloutId()); @@ -295,12 +305,10 @@ public class ConfigurableScenario { targetTagResource .createTargetTags(new TagBuilder().name("Page " + page) .description("Target tag for target page " + page).buildAsList(scenario.getTargetTags())) - .getBody().forEach( - tag -> targetTagResource.assignTargets(tag.getTagId(), - targets.stream() - .map(target -> new MgmtAssignedTargetRequestBody() - .setControllerId(target.getControllerId())) - .collect(Collectors.toList()))); + .getBody() + .forEach(tag -> targetTagResource.assignTargets(tag.getTagId(), targets.stream().map( + target -> new MgmtAssignedTargetRequestBody().setControllerId(target.getControllerId())) + .collect(Collectors.toList()))); } } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java index 9b3a37093..b2e4d91ae 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutProperties.java @@ -18,18 +18,31 @@ import org.springframework.stereotype.Component; @Component @ConfigurationProperties("hawkbit.rollout") public class RolloutProperties { + // used by @Scheduled annotation which needs constant + public static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.rollout.scheduler.fixedDelay:30000}"; + + // used by @Scheduled annotation which needs constant + public static final String PROP_CREATING_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.rollout.creatingScheduler.fixedDelay:2000}"; + + // used by @Scheduled annotation which needs constant + public static final String PROP_STARTING_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.rollout.startingScheduler.fixedDelay:2000}"; + /** * Rollout scheduler configuration. */ public static class Scheduler { - // used by @Scheduled annotation which needs constant - public static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.rollout.scheduler.fixedDelay:30000}"; /** * Schedule where the rollout scheduler looks necessary state changes in * milliseconds. */ - private long fixedDelay = 30000L; + private long fixedDelay; + + private boolean enabled = true; + + public Scheduler(final long fixedDelay) { + this.fixedDelay = fixedDelay; + } public long getFixedDelay() { return fixedDelay; @@ -39,12 +52,30 @@ public class RolloutProperties { this.fixedDelay = fixedDelay; } + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } } - private final Scheduler scheduler = new Scheduler(); + private final Scheduler scheduler = new Scheduler(30000L); + + private final Scheduler creatingScheduler = new Scheduler(2000L); + + private final Scheduler startingScheduler = new Scheduler(2000L); public Scheduler getScheduler() { return scheduler; } + public Scheduler getCreatingScheduler() { + return creatingScheduler; + } + + public Scheduler getStartingScheduler() { + return startingScheduler; + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index f423a7d11..63dcedef2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -90,7 +90,7 @@ public class JpaRolloutManagement implements RolloutManagement { * Maximum amount of targets that are assigned to a Rollout Group in one * transaction. */ - private static final long TRANSACTION_TARGETS = 1000; + private static final int TRANSACTION_TARGETS = 1000; @Autowired private EntityManager entityManager; @@ -376,14 +376,14 @@ public class JpaRolloutManagement implements RolloutManagement { } } - private Long runInNewCountingTransaction(final String transactionName, final TransactionCallback action) { + private int runInNewCountingTransaction(final String transactionName, final TransactionCallback action) { final DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setName(transactionName); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); return new TransactionTemplate(txManager, def).execute(action); } - private long assignTargetsToGroupInNewTransaction(final Rollout rollout, final RolloutGroup group, + private Integer assignTargetsToGroupInNewTransaction(final Rollout rollout, final RolloutGroup group, final String targetFilter, final long limit) { return runInNewCountingTransaction("assignTargetsToRolloutGroup", status -> { @@ -395,7 +395,7 @@ public class JpaRolloutManagement implements RolloutManagement { createAssignmentOfTargetsToGroup(targets, group); - return targets.getTotalElements(); + return targets.getNumberOfElements(); }); } @@ -552,9 +552,9 @@ public class JpaRolloutManagement implements RolloutManagement { return totalActionsCreated; } - private long createActionsForTargetsInNewTransaction(final long rolloutId, final long groupId, final long limit) { + private Integer createActionsForTargetsInNewTransaction(final long rolloutId, final long groupId, final int limit) { return runInNewCountingTransaction("createActionsForTargets", status -> { - final PageRequest pageRequest = new PageRequest(0, Math.toIntExact(limit)); + final PageRequest pageRequest = new PageRequest(0, limit); final Rollout rollout = rolloutRepository.findOne(rolloutId); final RolloutGroup group = rolloutGroupRepository.findOne(groupId); @@ -568,7 +568,7 @@ public class JpaRolloutManagement implements RolloutManagement { rollout, group); } - return targets.getTotalElements(); + return targets.getNumberOfElements(); }); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java index b02bb65bc..860afe2c2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/rollout/RolloutScheduler.java @@ -57,8 +57,12 @@ public class RolloutScheduler { * tenant the {@link RolloutManagement#checkRunningRollouts(long)} in the * {@link SystemSecurityContext}. */ - @Scheduled(initialDelayString = RolloutProperties.Scheduler.PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = RolloutProperties.Scheduler.PROP_SCHEDULER_DELAY_PLACEHOLDER) - public void rolloutScheduler() { + @Scheduled(initialDelayString = RolloutProperties.PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = RolloutProperties.PROP_SCHEDULER_DELAY_PLACEHOLDER) + public void runningRolloutScheduler() { + if (!rolloutProperties.getScheduler().isEnabled()) { + return; + } + LOGGER.debug("rollout schedule checker has been triggered."); // run this code in system code privileged to have the necessary // permission to query and create entities. @@ -74,8 +78,6 @@ public class RolloutScheduler { for (final String tenant : tenants) { tenantAware.runAsTenant(tenant, () -> { final long fixedDelay = rolloutProperties.getScheduler().getFixedDelay(); - rolloutManagement.checkCreatingRollouts(fixedDelay); - rolloutManagement.checkStartingRollouts(fixedDelay); rolloutManagement.checkRunningRollouts(fixedDelay); return null; }); @@ -83,4 +85,74 @@ public class RolloutScheduler { return null; }); } + + /** + * Scheduler method called by the spring-async mechanism. Retrieves all + * tenants from the {@link SystemManagement#findTenants()} and runs for each + * tenant the {@link RolloutManagement#checkStartingRollouts(long)} in the + * {@link SystemSecurityContext}. + */ + @Scheduled(initialDelayString = RolloutProperties.PROP_STARTING_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = RolloutProperties.PROP_STARTING_SCHEDULER_DELAY_PLACEHOLDER) + public void startingRolloutScheduler() { + if (!rolloutProperties.getStartingScheduler().isEnabled()) { + return; + } + + LOGGER.debug("rollout starting schedule checker has been triggered."); + // run this code in system code privileged to have the necessary + // permission to query and create entities. + systemSecurityContext.runAsSystem(() -> { + // workaround eclipselink that is currently not possible to + // execute a query without multitenancy if MultiTenant + // annotation is used. + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So + // iterate through all tenants and execute the rollout check for + // each tenant seperately. + final List tenants = systemManagement.findTenants(); + LOGGER.info("Checking starting rollouts for {} tenants", tenants.size()); + for (final String tenant : tenants) { + tenantAware.runAsTenant(tenant, () -> { + final long fixedDelay = rolloutProperties.getStartingScheduler().getFixedDelay(); + rolloutManagement.checkStartingRollouts(fixedDelay); + return null; + }); + } + return null; + }); + } + + /** + * Scheduler method called by the spring-async mechanism. Retrieves all + * tenants from the {@link SystemManagement#findTenants()} and runs for each + * tenant the {@link RolloutManagement#checkCreatingRollouts(long)} in the + * {@link SystemSecurityContext}. + */ + @Scheduled(initialDelayString = RolloutProperties.PROP_CREATING_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = RolloutProperties.PROP_CREATING_SCHEDULER_DELAY_PLACEHOLDER) + public void creatingRolloutScheduler() { + if (!rolloutProperties.getCreatingScheduler().isEnabled()) { + return; + } + + LOGGER.debug("rollout creating schedule checker has been triggered."); + // run this code in system code privileged to have the necessary + // permission to query and create entities. + systemSecurityContext.runAsSystem(() -> { + // workaround eclipselink that is currently not possible to + // execute a query without multitenancy if MultiTenant + // annotation is used. + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So + // iterate through all tenants and execute the rollout check for + // each tenant seperately. + final List tenants = systemManagement.findTenants(); + LOGGER.info("Checking creating rollouts for {} tenants", tenants.size()); + for (final String tenant : tenants) { + tenantAware.runAsTenant(tenant, () -> { + final long fixedDelay = rolloutProperties.getCreatingScheduler().getFixedDelay(); + rolloutManagement.checkCreatingRollouts(fixedDelay); + return null; + }); + } + return null; + }); + } }