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

io.gravitee.gateway.services.sync.SyncManager Maven / Gradle / Ivy

There is a newer version: 4.5.2
Show newest version
/*
 * Copyright © 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.gateway.services.sync;

import io.gravitee.common.service.AbstractService;
import io.gravitee.gateway.services.sync.synchronizer.ApiSynchronizer;
import io.gravitee.gateway.services.sync.synchronizer.DebugApiSynchronizer;
import io.gravitee.gateway.services.sync.synchronizer.DictionarySynchronizer;
import io.gravitee.gateway.services.sync.synchronizer.OrganizationSynchronizer;
import io.gravitee.node.api.cluster.ClusterManager;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

/**
 * @author David BRASSELY (david.brassely at graviteesource.com)
 * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
 * @author GraviteeSource Team
 */
public class SyncManager extends AbstractService {

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

    /**
     * Add 30s delay before and after to avoid problem with out of sync clocks.
     */
    public static final int TIMEFRAME_BEFORE_DELAY = 30000;
    public static final int TIMEFRAME_AFTER_DELAY = 30000;

    @Autowired
    private ApiSynchronizer apiSynchronizer;

    @Autowired
    private DictionarySynchronizer dictionarySynchronizer;

    @Autowired
    private OrganizationSynchronizer organizationSynchronizer;

    @Autowired
    private DebugApiSynchronizer debugApiSynchronizer;

    @Autowired
    private ClusterManager clusterManager;

    @Autowired
    @Qualifier("syncExecutor")
    private ThreadPoolExecutor executor;

    @Value("${services.sync.distributed:false}")
    private boolean distributed;

    private final AtomicLong counter = new AtomicLong(0);
    private long lastRefreshAt = -1;
    private int totalErrors = 0;
    private int errors = 0;
    private String lastErrorMessage;
    private final ThreadPoolTaskScheduler scheduler;
    private ScheduledFuture scheduledFuture;
    private boolean synced;
    private boolean allApisSync = false;
    private List environments;

    public SyncManager() {
        scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("gio.sync-master");
        // Ensure every execution is done before running next execution
        scheduler.setPoolSize(1);
        scheduler.initialize();
    }

    @Override
    protected void doStart() throws Exception {
        super.doStart();
        apiSynchronizer.start();
        dictionarySynchronizer.start();
        organizationSynchronizer.start();
        debugApiSynchronizer.start();
    }

    @Override
    protected void doStop() throws Exception {
        apiSynchronizer.stop();
        dictionarySynchronizer.stop();
        organizationSynchronizer.stop();
        debugApiSynchronizer.stop();

        if (scheduledFuture != null) {
            scheduledFuture.cancel(false);
        }

        if (scheduler != null) {
            scheduler.shutdown();
        }

        super.doStop();
    }

    public void startScheduler(int delay, TimeUnit unit) {
        scheduledFuture = scheduler.scheduleAtFixedRate(this::refresh, Duration.ofMillis(unit.toMillis(delay)));
    }

    public void refresh() {
        final long nextLastRefreshAt = System.currentTimeMillis();
        boolean error = false;

        if (clusterManager.isMasterNode() || (!clusterManager.isMasterNode() && !distributed)) {
            logger.debug("Synchronization #{} started at {}", counter.incrementAndGet(), Instant.now().toString());
            logger.debug("Refreshing gateway state...");

            try {
                organizationSynchronizer.synchronize(lastRefreshAt, nextLastRefreshAt, environments);
            } catch (Exception ex) {
                error = true;
                lastErrorMessage = ex.getMessage();
                logger.error("An error occurs while synchronizing organizations", ex);
            }

            try {
                apiSynchronizer.synchronize(lastRefreshAt, nextLastRefreshAt, environments);
            } catch (Exception ex) {
                error = true;
                lastErrorMessage = ex.getMessage();
                logger.error("An error occurs while synchronizing APIs", ex);
            }

            try {
                dictionarySynchronizer.synchronize(lastRefreshAt, nextLastRefreshAt, environments);
            } catch (Exception ex) {
                error = true;
                lastErrorMessage = ex.getMessage();
                logger.error("An error occurs while synchronizing dictionaries", ex);
            }

            try {
                debugApiSynchronizer.synchronize(lastRefreshAt, nextLastRefreshAt, environments);
            } catch (Exception ex) {
                error = true;
                lastErrorMessage = ex.getMessage();
                logger.error("An error occurs while synchronizing debug APIs", ex);
            }

            if (error) {
                errors++;
                totalErrors++;
            } else {
                errors = 0;
            }
        }

        // If there was no error during the sync process, let's continue it with the next period of time
        if (!error) {
            allApisSync = true;

            if (lastRefreshAt == -1) {
                // When first sync is entirely done, we can reduce number of threads to the minimum for next sync
                executor.setCorePoolSize(1);

                // A first full sync has been done
                synced = true;
            }
            // We refresh the date even if process did not run (not a master node) to ensure that we sync the same way as
            // soon as the node is becoming the master later.
            lastRefreshAt = nextLastRefreshAt;
        }

        logger.debug(
            "Synchronization #{} ended at {} (took {}ms}",
            counter.get(),
            Instant.now().toString(),
            System.currentTimeMillis() - nextLastRefreshAt
        );
    }

    public boolean isDistributed() {
        return distributed;
    }

    public void setDistributed(boolean distributed) {
        this.distributed = distributed;
    }

    public long getLastRefreshAt() {
        return lastRefreshAt;
    }

    public long getCounter() {
        return counter.longValue();
    }

    /**
     * This method returns if a first full sync occurs successfully.
     * @return
     */
    public boolean isSynced() {
        return synced;
    }

    public int getTotalErrors() {
        return totalErrors;
    }

    public int getErrors() {
        return errors;
    }

    public String getLastErrorMessage() {
        return lastErrorMessage;
    }

    public boolean isAllApisSync() {
        return allApisSync;
    }

    public List getEnvironments() {
        return environments;
    }

    public void setEnvironments(List environments) {
        this.environments = environments;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy