001/*
002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.cuioss.http.client.retry;
017
018import java.time.Duration;
019
020/**
021 * Interface for recording retry operation metrics.
022 * <p>
023 * This interface provides a clean abstraction for metrics recording that can be
024 * implemented by different metrics systems (Micrometer, custom metrics, etc.)
025 * without creating dependencies in the core retry infrastructure.
026 * <p>
027 * All methods in this interface should be implemented to be non-blocking and
028 * should handle any internal exceptions gracefully to avoid impacting retry logic.
029 */
030public interface RetryMetrics {
031
032    /**
033     * Records the start of a complete retry operation.
034     * This should be called once per retry operation, before any attempts.
035     *
036     * @param context retry context information
037     */
038    void recordRetryStart(RetryContext context);
039
040    /**
041     * Records the completion of a retry operation (success or failure after all attempts).
042     *
043     * @param context retry context information
044     * @param totalDuration total duration including all attempts and delays
045     * @param successful whether the retry operation ultimately succeeded
046     * @param totalAttempts total number of attempts made
047     */
048    void recordRetryComplete(RetryContext context, Duration totalDuration, boolean successful, int totalAttempts);
049
050    /**
051     * Records a single retry attempt.
052     *
053     * @param context retry context information
054     * @param attemptNumber the attempt number (1-based)
055     * @param attemptDuration duration of this specific attempt (excluding delay)
056     * @param successful whether this specific attempt succeeded
057     */
058    void recordRetryAttempt(RetryContext context, int attemptNumber, Duration attemptDuration,
059                            boolean successful);
060
061    /**
062     * Records the actual delay time between retry attempts.
063     *
064     * @param context retry context information
065     * @param attemptNumber the attempt number that will follow this delay
066     * @param plannedDelay the calculated delay duration
067     * @param actualDelay the actual delay duration (may differ due to interruption)
068     */
069    void recordRetryDelay(RetryContext context, int attemptNumber, Duration plannedDelay, Duration actualDelay);
070
071    /**
072     * Creates a no-op implementation that performs no metrics recording.
073     * Useful when metrics are disabled or not available.
074     *
075     * @return a metrics recorder that does nothing
076     */
077    static RetryMetrics noOp() {
078        return NoOpRetryMetrics.INSTANCE;
079    }
080
081    /**
082     * No-op implementation for when metrics are disabled.
083     */
084    @SuppressWarnings("java:S6548")
085    final class NoOpRetryMetrics implements RetryMetrics {
086        static final NoOpRetryMetrics INSTANCE = new NoOpRetryMetrics();
087
088        private NoOpRetryMetrics() {
089        }
090
091        @Override
092        public void recordRetryStart(RetryContext context) {
093            // No-op
094        }
095
096        @Override
097        public void recordRetryComplete(RetryContext context, Duration totalDuration, boolean successful, int totalAttempts) {
098            // No-op
099        }
100
101        @Override
102        public void recordRetryAttempt(RetryContext context, int attemptNumber, Duration attemptDuration,
103                                       boolean successful) {
104            // No-op
105        }
106
107        @Override
108        public void recordRetryDelay(RetryContext context, int attemptNumber, Duration plannedDelay, Duration actualDelay) {
109            // No-op
110        }
111    }
112}