001package ca.uhn.fhir.util;
002
003/*-
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2023 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.system.HapiSystemProperties;
025import com.google.common.annotations.VisibleForTesting;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029import java.time.Duration;
030
031public class TimeoutManager {
032        private static final Logger ourLog = LoggerFactory.getLogger(TimeoutManager.class);
033
034        private final StopWatch myStopWatch = new StopWatch();
035        private final String myServiceName;
036        private final Duration myWarningTimeout;
037        private final Duration myErrorTimeout;
038
039        private boolean warned = false;
040        private boolean errored = false;
041
042        public TimeoutManager(String theServiceName, Duration theWarningTimeout, Duration theErrorTimeout) {
043                myServiceName = theServiceName;
044                myWarningTimeout = theWarningTimeout;
045                myErrorTimeout = theErrorTimeout;
046        }
047
048        /**
049         *
050         * @return true if a message was logged
051         */
052        public boolean checkTimeout() {
053                boolean retval = false;
054                if (myStopWatch.getMillis() > myWarningTimeout.toMillis() && !warned) {
055                        ourLog.warn(myServiceName + " has run for {}", myStopWatch);
056                        warned = true;
057                        retval = true;
058                }
059                if (myStopWatch.getMillis() > myErrorTimeout.toMillis() && !errored) {
060                        if (HapiSystemProperties.isUnitTestModeEnabled()) {
061                                throw new TimeoutException(Msg.code(2133) + myServiceName + " timed out after running for " + myStopWatch);
062                        } else {
063                                ourLog.error(myServiceName + " has run for {}", myStopWatch);
064                                errored = true;
065                                retval = true;
066                        }
067                }
068                return retval;
069        }
070
071        @VisibleForTesting
072        void addTimeForUnitTest(Duration theDuration) {
073                myStopWatch.setNowForUnitTest(myStopWatch.getStartedDate().getTime() + theDuration.toMillis());
074        }
075}