<commit_before>package com.swisscom.cloud.sb.broker.cleanup;

import com.google.common.base.Stopwatch;
import com.swisscom.cloud.sb.broker.model.ServiceInstance;
import com.swisscom.cloud.sb.broker.repository.ServiceInstanceRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static java.lang.String.format;

public class CleanupService {
    protected static final Logger LOGGER = LoggerFactory.getLogger(CleanupService.class);

    private final CleanupServiceConfiguration cleanupServiceConfiguration;
    private final CleanupInfoService cleanupInfoService;
    private final ServiceInstanceRepository serviceInstanceRepository;
    private final AlertingClient alertingClient;
    private final CleanupAction cleanupAction;

    CleanupService(CleanupServiceConfiguration cleanupServiceConfiguration,
                   CleanupInfoService cleanupInfoService,
                   ServiceInstanceRepository serviceInstanceRepository,
                   AlertingClient alertingClient,
                   CleanupAction cleanupAction) {
        this.cleanupServiceConfiguration = cleanupServiceConfiguration;
        this.cleanupInfoService = cleanupInfoService;
        this.serviceInstanceRepository = serviceInstanceRepository;
        this.alertingClient = alertingClient;
        this.cleanupAction = cleanupAction;
    }

    public void triggerCleanup() {
        LOGGER.debug("triggerCleanup()");

        Mono.when(listCleanupServiceInstances().stream()
                .map(this::triggerServiceInstanceCleanup)
                .collect(Collectors.toList()))
                .block();

        LOGGER.debug("triggerCleanup() >> done");
    }

    public void triggerCleanup(String serviceInstanceUuid) {
        triggerServiceInstanceCleanup(serviceInstanceRepository.findByGuid(serviceInstanceUuid)).block();
    }

    private Mono<Boolean> triggerServiceInstanceCleanup(ServiceInstance serviceInstance) {
        return Mono.just(serviceInstance.getGuid())
                .publishOn(Schedulers.boundedElastic())
                .flatMap(cleanupAction::executeCleanupServiceInstance)
                .onErrorResume(ex -> {
                    handleException(serviceInstance, ex);
                    return Mono.just(false);
                })
                .doOnNext(r -> {
                    if (r) {
                        cleanupInfoService.setCompletedState(serviceInstance.getGuid());
                    }
                });
    }

    private void handleException(ServiceInstance serviceInstance, Throwable ex) {
        alertingClient.alert(Failure.builder()
                .message(format("Cleanup ServiceInstance failed for %s", serviceInstance.getGuid()))
                .description(format("Error during cleanup: %s", ex.getMessage()))
                .exception(ex)
                .build());
    }

    private List<ServiceInstance> listCleanupServiceInstances() {
        Stopwatch watch = Stopwatch.createStarted();
        List<ServiceInstance> result = serviceInstanceRepository.findAll()
                .stream()
                .filter(ServiceInstance::isDeleted)
                .filter(this::isAfterCleanupOffset)
                .filter(this::isNotCleanupCompleted)
                .collect(Collectors.toList());

        LOGGER.info("Found {} service instances for cleanup, took: {}ms", result.size(), watch.elapsed(TimeUnit.MILLISECONDS));
        return result;
    }

    private boolean isNotCleanupCompleted(ServiceInstance serviceInstance) {
        return !cleanupInfoService.isCompletedState(serviceInstance.getGuid());
    }

    private boolean isAfterCleanupOffset(ServiceInstance serviceInstance) {
        LOGGER.info("isAfterCleanupOffset({})", serviceInstance);
        return serviceInstance.getDateDeleted().toInstant()
                .plus(cleanupServiceConfiguration.getCleanupThresholdInDays(), ChronoUnit.DAYS)
                .isBefore(Instant.now());
    }
}<commit_msg>fix: check if deleted is defined.<commit_after>package com.swisscom.cloud.sb.broker.cleanup;

import com.google.common.base.Stopwatch;
import com.swisscom.cloud.sb.broker.model.ServiceInstance;
import com.swisscom.cloud.sb.broker.repository.ServiceInstanceRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static java.lang.String.format;

public class CleanupService {
    protected static final Logger LOGGER = LoggerFactory.getLogger(CleanupService.class);

    private final CleanupServiceConfiguration cleanupServiceConfiguration;
    private final CleanupInfoService cleanupInfoService;
    private final ServiceInstanceRepository serviceInstanceRepository;
    private final AlertingClient alertingClient;
    private final CleanupAction cleanupAction;

    CleanupService(CleanupServiceConfiguration cleanupServiceConfiguration,
                   CleanupInfoService cleanupInfoService,
                   ServiceInstanceRepository serviceInstanceRepository,
                   AlertingClient alertingClient,
                   CleanupAction cleanupAction) {
        this.cleanupServiceConfiguration = cleanupServiceConfiguration;
        this.cleanupInfoService = cleanupInfoService;
        this.serviceInstanceRepository = serviceInstanceRepository;
        this.alertingClient = alertingClient;
        this.cleanupAction = cleanupAction;
    }

    public void triggerCleanup() {
        LOGGER.debug("triggerCleanup()");

        Mono.when(listCleanupServiceInstances().stream()
                .map(this::triggerServiceInstanceCleanup)
                .collect(Collectors.toList()))
                .block();

        LOGGER.debug("triggerCleanup() >> done");
    }

    public void triggerCleanup(String serviceInstanceUuid) {
        triggerServiceInstanceCleanup(serviceInstanceRepository.findByGuid(serviceInstanceUuid)).block();
    }

    private Mono<Boolean> triggerServiceInstanceCleanup(ServiceInstance serviceInstance) {
        return Mono.just(serviceInstance.getGuid())
                .publishOn(Schedulers.boundedElastic())
                .flatMap(cleanupAction::executeCleanupServiceInstance)
                .onErrorResume(ex -> {
                    handleException(serviceInstance, ex);
                    return Mono.just(false);
                })
                .doOnNext(r -> {
                    if (r) {
                        cleanupInfoService.setCompletedState(serviceInstance.getGuid());
                    }
                });
    }

    private void handleException(ServiceInstance serviceInstance, Throwable ex) {
        alertingClient.alert(Failure.builder()
                .message(format("Cleanup ServiceInstance failed for %s", serviceInstance.getGuid()))
                .description(format("Error during cleanup: %s", ex.getMessage()))
                .exception(ex)
                .build());
    }

    private List<ServiceInstance> listCleanupServiceInstances() {
        Stopwatch watch = Stopwatch.createStarted();
        List<ServiceInstance> result = serviceInstanceRepository.findAll()
                .stream()
                .filter(ServiceInstance::isDeleted)
                .filter(this::isDeletedDefined)
                .filter(this::isAfterCleanupOffset)
                .filter(this::isNotCleanupCompleted)
                .collect(Collectors.toList());

        LOGGER.info("Found {} service instances for cleanup, took: {}ms", result.size(), watch.elapsed(TimeUnit.MILLISECONDS));
        return result;
    }

    private boolean isNotCleanupCompleted(ServiceInstance serviceInstance) {
        return !cleanupInfoService.isCompletedState(serviceInstance.getGuid());
    }

    private boolean isDeletedDefined(ServiceInstance serviceInstance) {
        return serviceInstance.getDateDeleted() != null;
    }

    private boolean isAfterCleanupOffset(ServiceInstance serviceInstance) {
        LOGGER.info("isAfterCleanupOffset({})", serviceInstance);
        return serviceInstance.getDateDeleted().toInstant()
                .plus(cleanupServiceConfiguration.getCleanupThresholdInDays(), ChronoUnit.DAYS)
                .isBefore(Instant.now());
    }
}
{'fraction_non_alphanumeric': 0.08790060380863911, 'fraction_numerical': 0.00046446818392940084, 'mean_word_length': 2.96, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3960515', 'n_tokens_mistral': 2150, 'n_tokens_neox': 2069, 'n_words': 357}