/**
 * Copyright 2020 Opstrace, Inc.
 *
 * 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.
 */ import { EventEmitter } from "events" ; import { log } from "./log" ; export function sleep ( seconds ) { return new Promise ( resolve => setTimeout ( resolve , seconds * 1000.0 ) ) ; } export function mtime ( ) { return process . hrtime . bigint ( ) ; } param ref returns export function mtimeDiffSeconds ( ref ) { return Number ( process . hrtime . bigint ( ) - ref ) / 10 ** 9 ; } export function mtimeDeadlineInSeconds ( seconds ) { return process . hrtime . bigint ( ) + BigInt ( seconds * 10 ** 9 ) ; } export function mtimeDeadlineTimeLeftSeconds ( deadline ) { return Number ( deadline - process . hrtime . bigint ( ) ) / 10 ** 9 ; } export function timeoutTerminator ( timeoutSeconds ) { const loopIntervalSeconds = 1.0 ; const maxReportDelaySeconds = 60 * 3 ; const timeoutCanceller = new EventEmitter ( ) ; let cancelled = false ; new Promise ( async function ( resolvefunc , _ ) { timeoutCanceller . once ( "cancel" , ( ) => { log . debug ( "timeoutTerminator: cancel event received" ) ; cancelled = true ; } ) ; const deadlineTerminate = mtimeDeadlineInSeconds ( timeoutSeconds ) ; const reportIntervalSeconds = Math . min ( maxReportDelaySeconds , timeoutSeconds / 5.0 ) ; let deadlineReport = mtimeDeadlineInSeconds ( reportIntervalSeconds ) ; function report ( ) { const s = mtimeDeadlineTimeLeftSeconds ( deadlineTerminate ) ; log . info ( "timeoutTerminator: %s s (%s min) remaining" , s . toFixed ( 1 ) , ( s / 60.0 ) . toFixed ( 1 ) ) ; deadlineReport = mtimeDeadlineInSeconds ( reportIntervalSeconds ) ; } report ( ) ; while ( ! cancelled ) { if ( mtime ( ) > deadlineTerminate ) { log . error ( "timeoutTerminator: deadline hit. terminate process." ) ; process . exit ( 1 ) ; } if ( mtime ( ) > deadlineReport ) { report ( ) ; } await sleep ( loopIntervalSeconds ) ; } log . info ( "timeoutTerminator: cancelled" ) ; resolvefunc ( ) ; } ) ; return timeoutCanceller ; }