All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.am.management.services.sync.SyncManager Maven / Gradle / Ivy

There is a newer version: 4.6.0-alpha.2
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gravitee.am.management.services.sync;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.gravitee.am.model.common.event.Event;
import io.gravitee.am.monitoring.metrics.Constants;
import io.gravitee.am.monitoring.metrics.GaugeHelper;
import io.gravitee.am.service.EventService;
import io.gravitee.common.event.EventManager;
import io.reactivex.rxjava3.core.Single;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.BinaryOperator;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toMap;

/**
 * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
 * @author GraviteeSource Team
 */
public class SyncManager implements InitializingBean {
    public static final int TIMEFRAME_BEFORE_DELAY = 30000;
    public static final int TIMEFRAME_AFTER_DELAY = 30000;

    private final Logger logger = LoggerFactory.getLogger(SyncManager.class);

    @Autowired
    private EventService eventService;

    @Autowired
    private EventManager eventManager;

    @Value("${services.sync.timeframeBeforeDelay:"+TIMEFRAME_BEFORE_DELAY+"}")
    private int timeframeBeforeDelay;

    @Value("${services.sync.timeframeAfterDelay:"+TIMEFRAME_AFTER_DELAY+"}")
    private int timeframeAfterDelay;

    private long lastRefreshAt = System.currentTimeMillis();

    private long lastDelay = 0;

    private GaugeHelper eventsGauge = new GaugeHelper(Constants.METRICS_EVENTS_SYNC);

    @Value("${services.sync.eventsTimeOutMillis:30000}")
    private int eventsTimeOut = 30000;

    private Cache processedEventIds;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.processedEventIds = CacheBuilder.newBuilder()
                .expireAfterWrite(timeframeBeforeDelay + timeframeAfterDelay, TimeUnit.MILLISECONDS)
                .build();
    }

    public void refresh() {
        logger.debug("Refreshing sync state...");

        try {
            processEvents();
        } catch (Exception ex) {
            logger.error("An error occurs while synchronizing organizations", ex);
        }
    }

    private void processEvents() {

        long nextLastRefreshAt = System.currentTimeMillis();

        // search for events and compute them
        logger.debug("Events synchronization");

        final long from = (lastRefreshAt - lastDelay) - timeframeBeforeDelay;
        final long to = nextLastRefreshAt + timeframeAfterDelay;
        Single> eventsProcessing = eventService.findByTimeFrame(from, to);
        if (eventsTimeOut > 0) {
            eventsProcessing = eventsProcessing.timeout(eventsTimeOut, TimeUnit.MILLISECONDS);
        }
        List events = eventsProcessing.blockingGet();

        if (events != null && !events.isEmpty()) {
            eventsGauge.updateValue(events.size());
            // Extract only the latest events by type and id
            Map sortedEvents = events
                    .stream()
                    .collect(
                            toMap(
                                    event -> new AbstractMap.SimpleEntry<>(event.getType(), event.getPayload().getId()),
                                    event -> event, BinaryOperator.maxBy(comparing(Event::getCreatedAt)), LinkedHashMap::new));
            computeEvents(sortedEvents.values());
        } else {
            eventsGauge.updateValue(0);
        }

        lastRefreshAt = nextLastRefreshAt;
        lastDelay = System.currentTimeMillis() - nextLastRefreshAt;

    }

    private void computeEvents(Collection events) {
        events.forEach(event -> {
            if (Objects.isNull(processedEventIds.getIfPresent(event.getId()))) {
                logger.debug("Compute event id : {}, with type : {} and timestamp : {} and payload : {}", event.getId(), event.getType(), event.getCreatedAt(), event.getPayload());

                final var commonEvent = io.gravitee.am.common.event.Event.valueOf(event.getType(), event.getPayload().getAction());
                if(commonEvent == null){
                    logger.debug("Cannot publish event {} as type is null", event.getId());
                    return;
                }

                eventManager.publishEvent(commonEvent, event.getPayload());
            } else {
                logger.debug("Event id {} already processed", event.getId());
            }
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy