For the special case of cancelling timers, that is futures returned by `sleepAsync`, I have an implementation. It is a bit hacky though as it manipulates the dispatcher's timer list: proc cancelTimer*(timer: Future[void], error: ref CatchableError) = let dispatcher = getGlobalDispatcher() if dispatcher.timers.len() > 0: for i in 0 ..< dispatcher.timers.len(): if dispatcher.timers[i].fut == timer: dispatcher.timers[i].fut.fail(error) dispatcher.timers.del(i) return Run
With this, I would implement your ticker example like this: import std/[asyncdispatch, times, asyncfutures] import std/[strutils, strformat] import std/heapqueue type Canceled = object of CatchableError type Ticker = ref object ident: int stop: int interval: int timer: Future[void] canceled: bool proc cancelTimer*(timer: Future[void], error: ref CatchableError) = let dispatcher = getGlobalDispatcher() if dispatcher.timers.len() > 0: for i in 0 ..< dispatcher.timers.len(): if dispatcher.timers[i].fut == timer: dispatcher.timers[i].fut.fail(error) dispatcher.timers.del(i) return proc start(ticker: Ticker) {.async.} = var remain = ticker.stop while remain > 0: if ticker.canceled: break echo &"tick#{ticker.ident}: ", now() dec remain ticker.timer = sleepAsync(ticker.interval) try: await ticker.timer except Canceled: break echo &"tick#{ticker.ident}: exiting" proc cancel(ticker: Ticker) = cancelTimer(ticker.timer, newException(Canceled, "timer was canceled")) ticker.canceled = true proc cancelAfter(ticker: Ticker, timeout: int) {.async.} = await sleepAsync(timeout) ticker.cancel() proc run(ticker1, ticker2: Ticker) {.async.} = asyncCheck ticker1.cancelAfter(1000) await ticker1.start() asyncCheck ticker2.cancelAfter(5000) await ticker2.start() proc main: int = asyncCheck run(Ticker(ident: 1, stop: 3, interval: 500, canceled: false), Ticker(ident: 2, stop: 3, interval: 500, canceled: false)) while hasPendingOperations(): poll(high(int)) when isMainModule: quit main() Run