@@ -665,6 +665,7 @@ function maybePromise(callback, wrapper) {
665
665
function databaseNamespace ( ns ) {
666
666
return ns . split ( '.' ) [ 0 ] ;
667
667
}
668
+
668
669
function collectionNamespace ( ns ) {
669
670
return ns
670
671
. split ( '.' )
@@ -915,6 +916,89 @@ function emitDeprecatedOptionWarning(options, list) {
915
916
} ) ;
916
917
}
917
918
919
+ function now ( ) {
920
+ const hrtime = process . hrtime ( ) ;
921
+ return Math . floor ( hrtime [ 0 ] * 1000 + hrtime [ 1 ] / 1000000 ) ;
922
+ }
923
+
924
+ /**
925
+ * Creates an interval timer which is able to be woken up sooner than
926
+ * the interval. The timer will also debounce multiple calls to wake
927
+ * ensuring that the function is only ever called once within a minimum
928
+ * interval window.
929
+ *
930
+ * @param {function } fn An async function to run on an interval, must accept a `callback` as its only parameter
931
+ * @param {object } [options] Optional settings
932
+ * @param {number } [options.interval] The interval at which to run the provided function
933
+ * @param {number } [options.minInterval] The minimum time which must pass between invocations of the provided function
934
+ * @param {boolean } [options.immediate] Execute the function immediately when the interval is started
935
+ */
936
+ function makeInterruptableAsyncInterval ( fn , options ) {
937
+ let timerId ;
938
+ let lastCallTime ;
939
+ let lastWakeTime ;
940
+ let stopped = false ;
941
+
942
+ options = options || { } ;
943
+ const interval = options . interval || 1000 ;
944
+ const minInterval = options . minInterval || 500 ;
945
+ const immediate = typeof options . immediate === 'boolean' ? options . immediate : false ;
946
+
947
+ function wake ( ) {
948
+ const currentTime = now ( ) ;
949
+ const timeSinceLastWake = currentTime - lastWakeTime ;
950
+ const timeSinceLastCall = currentTime - lastCallTime ;
951
+ const timeUntilNextCall = Math . max ( interval - timeSinceLastCall , 0 ) ;
952
+ lastWakeTime = currentTime ;
953
+
954
+ // debounce multiple calls to wake within the `minInterval`
955
+ if ( timeSinceLastWake < minInterval ) {
956
+ return ;
957
+ }
958
+
959
+ // reschedule a call as soon as possible, ensuring the call never happens
960
+ // faster than the `minInterval`
961
+ if ( timeUntilNextCall > minInterval ) {
962
+ reschedule ( minInterval ) ;
963
+ }
964
+ }
965
+
966
+ function stop ( ) {
967
+ stopped = true ;
968
+ if ( timerId ) {
969
+ clearTimeout ( timerId ) ;
970
+ timerId = null ;
971
+ }
972
+
973
+ lastCallTime = 0 ;
974
+ lastWakeTime = 0 ;
975
+ }
976
+
977
+ function reschedule ( ms ) {
978
+ if ( stopped ) return ;
979
+ clearTimeout ( timerId ) ;
980
+ timerId = setTimeout ( executeAndReschedule , ms || interval ) ;
981
+ }
982
+
983
+ function executeAndReschedule ( ) {
984
+ lastWakeTime = 0 ;
985
+ lastCallTime = now ( ) ;
986
+ fn ( err => {
987
+ if ( err ) throw err ;
988
+ reschedule ( interval ) ;
989
+ } ) ;
990
+ }
991
+
992
+ if ( immediate ) {
993
+ executeAndReschedule ( ) ;
994
+ } else {
995
+ lastCallTime = now ( ) ;
996
+ reschedule ( ) ;
997
+ }
998
+
999
+ return { wake, stop } ;
1000
+ }
1001
+
918
1002
module . exports = {
919
1003
filterOptions,
920
1004
mergeOptions,
@@ -957,5 +1041,7 @@ module.exports = {
957
1041
errorStrictEqual,
958
1042
makeStateMachine,
959
1043
makeClientMetadata,
960
- noop
1044
+ noop,
1045
+ now,
1046
+ makeInterruptableAsyncInterval
961
1047
} ;
0 commit comments