add CancellationToken support