I have the following code which run the passed proc in an interval, and return a clearInterval proc to stop the run, as follow:
proc runInterval(cb: proc, interval: int): Future[proc()] {.async.} =
  var stop_run = false
  while not(stop_run):
    await sleepAsync(intv)
    cb()
  
  proc clearInterval() =
    stop_run = true
  
  return clearInterval
proc in_interval() =
  echo "hahah"
let clearInterval = runInterval(in_interval, 1000) # run the in_interval proc every 1 second
clearInterval() # stop in_interval
runForever()
I suspect type annotation of runInterval is not correct as
: Future[proc()] {.async.} Maybe what you want is async with cancelation?
Chronos supports that, and mashingan gave an example for Nim async here:
I guess this is what you want.
import asyncdispatch
type
  Action = proc(): void {.gcsafe.}
proc runInterval(cb: Action, interval: int): Future[Action] {.async.} =
  var running = true
  result = proc() =
    running = false
  
  proc loop() =
    if running:
      addTimer interval, true, proc(fd: AsyncFD): bool =
        if running:
          cb()
          loop()
  loop()
proc main() {.async.} =
  var stop: Action
  
  var called = 0
  proc callback() {.gcsafe.} =
    # stop after called three times
    called.inc
    echo "called=", called
    if called >= 3:
      echo "stopping "
      stop()
  
  # run the in_interval proc every 1 second
  stop = await runInterval(callback, 1000)
when isMainModule:
  asyncCheck main()
  while hasPendingOperations():
    poll()
Thanks for all the replies! It looks like the most elegant/simple way to "clear" an interval is to using chronos library,
import chronos
proc test() {.async.} =
  while true:
    await sleepAsync(1000)
    echo "test"
proc run() {.async.} =
  let fut = test()
  await sleepAsync(4000)
  fut.cancel()
waitFor(run())
and that's exactlly what I want: fire up number of jobs running in time interval, and cancel them unconditionally using the handler (fut). @jackhftang's solution works but I think chronos is easier / simpler.