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

com.taboola.async_profiler.api.AsyncProfilerService Maven / Gradle / Ivy

package com.taboola.async_profiler.api;

import lombok.SneakyThrows;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.taboola.async_profiler.api.continuous.ContinuousProfilingSnapshotRequest;
import com.taboola.async_profiler.api.continuous.ProfileResultsReporter;
import com.taboola.async_profiler.api.facade.AsyncProfilerFacade;
import com.taboola.async_profiler.api.facade.ProfileRequest;
import com.taboola.async_profiler.api.facade.ProfileResult;
import com.taboola.async_profiler.api.serviceconfig.AsyncProfilerServiceConfigurations;
import com.taboola.async_profiler.utils.RecurringRunnable;
import com.taboola.async_profiler.utils.ThreadUtils;

public class AsyncProfilerService {

    private static Logger logger = LoggerFactory.getLogger(AsyncProfilerService.class);

    private final AsyncProfilerFacade asyncProfilerFacade;
    private final ProfileResultsReporter profileResultsReporter;
    private final ExecutorService continuousProfilingExecutorService;
    private final ExecutorService snapshotsReporterExecutorService;
    private final long continuousProfilingFailureBackoffSeconds;
    private final ThreadUtils threadUtils;
    private final Object lock;
    private volatile RecurringRunnable currentContinuousProfilingTask;

    public AsyncProfilerService(AsyncProfilerFacade asyncProfilerFacade,
                                ProfileResultsReporter profileResultsReporter,
                                ExecutorService continuousProfilingExecutorService,
                                ExecutorService snapshotsReporterExecutorService,
                                AsyncProfilerServiceConfigurations asyncProfilerConfigurations,
                                ThreadUtils threadUtils) {
        this.asyncProfilerFacade = asyncProfilerFacade;
        this.profileResultsReporter = profileResultsReporter;
        this.continuousProfilingExecutorService = continuousProfilingExecutorService;
        this.snapshotsReporterExecutorService = snapshotsReporterExecutorService;
        this.continuousProfilingFailureBackoffSeconds = asyncProfilerConfigurations.getContinuousProfiling().getFailureBackoffSeconds();
        this.threadUtils = threadUtils;
        this.lock = new Object();

        if (asyncProfilerConfigurations.getContinuousProfiling().isStartOnInit()) {
            startContinuousProfiling(asyncProfilerConfigurations.getContinuousProfiling().getSnapshotRequest());
        }
    }

    public ProfileResult profile(ProfileRequest profileRequest) {
        return asyncProfilerFacade.profile(profileRequest);
    }

    public ProfileResult stop() {
        return asyncProfilerFacade.stop();
    }

    public void startContinuousProfiling(ContinuousProfilingSnapshotRequest continuousProfilingSnapshotRequest) {
        synchronized (lock) {
            if (currentContinuousProfilingTask == null) {
                RecurringRunnable continuousProfilingTask = new RecurringRunnable(() -> profileAndReportSnapshot(continuousProfilingSnapshotRequest));
                continuousProfilingExecutorService.submit(continuousProfilingTask);
                currentContinuousProfilingTask = continuousProfilingTask;
            } else {
                throw new IllegalStateException("Failed starting continuous profiling, there is already an active session");
            }
        }
    }

    public void stopContinuousProfiling() {
        synchronized (lock) {
            if (currentContinuousProfilingTask != null) {
                currentContinuousProfilingTask.cancel();
                currentContinuousProfilingTask = null;
                safeStop();
            } else {
                throw new IllegalStateException("There is no active continuous profiling session");
            }
        }
    }

    public boolean isContinuousProfilingActive() {
        return currentContinuousProfilingTask != null;
    }

    public String getSupportedEvents() {
        return asyncProfilerFacade.getSupportedEvents();
    }

    public String getProfilerVersion() {
        return asyncProfilerFacade.getProfilerVersion();
    }

    @SneakyThrows
    private void profileAndReportSnapshot(ContinuousProfilingSnapshotRequest continuousProfilingSnapshotRequest) {
        try {
            ProfileResult profileSnapshotResult = asyncProfilerFacade.profile(continuousProfilingSnapshotRequest);
            reportAsync(profileSnapshotResult);

        } catch (RuntimeException ex) {
            logger.error("Failed submitting profile result {}, sleeping for {} seconds", ex, continuousProfilingFailureBackoffSeconds);
            //sleep for backoff seconds if the profiler has failed or if we failed to submit the result to the reporter executor service
            //we will throw from here only if we failed to sleep because it was interrupted, which is ok
            threadUtils.sleep(continuousProfilingFailureBackoffSeconds, TimeUnit.SECONDS);
        }
    }

    private void reportAsync(ProfileResult profileSnapshotResult) {
        try {
            snapshotsReporterExecutorService.submit(() -> reportSnapshot(profileSnapshotResult));
        } catch (Exception ex) {
            if (profileSnapshotResult != null) {
                try {
                    profileSnapshotResult.close();
                } catch (Exception e) {
                    logger.error("Failed closing profile result", e);
                }
            }

            throw new RuntimeException(ex);
        }
    }

    private void reportSnapshot(ProfileResult snapshotResult) {
        try (ProfileResult profileResult = snapshotResult) {
            profileResultsReporter.report(profileResult);
        } catch (Exception ex) {
            logger.error("Unexpected error in profile results reporter", ex);
        }
    }

    private void safeStop() {
        try {
            stop();
        } catch (RuntimeException e) {}
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy