Table of Contents

Write asynchronous code

Raven uses .NET's task and async-stream types with async, await, and await for.

Await a task

Mark a function async and await the asynchronous operation:

import System.Net.Http.*
import System.Threading.Tasks.*

async func DownloadLength(url: string) -> Task<int> {
    use http = HttpClient()
    let text = await http.GetStringAsync(url)
    return text.Length
}

The return type remains a normal .NET Task<T>, so Raven functions can call and be called by existing .NET libraries.

Await in exception handlers

An async function may suspend in catch and finally blocks, including at multiple await points in the same handler:

try {
    await ProcessAsync()
} catch (Exception ex) {
    await LogAsync(ex)
    await RecoverAsync()
} finally {
    await FlushAsync()
    await CloseAsync()
}

Returns, handled and unhandled exceptions, and surrounding control flow keep their normal .NET ordering. A finally block completes all of its awaits before the pending return or exception continues.

Consume an async stream

Use await for with IAsyncEnumerable<T>:

await for reading in telemetry.Poll(cancellationToken) {
    Console.WriteLine(reading)
}

An async iterator can produce values with yield and await between them. This works well for streaming endpoints, telemetry, and incremental data sources.

Carry cancellation across boundaries

Accept a CancellationToken when the caller owns the operation lifetime and pass it to the .NET APIs you await. Do not replace cancellation with a custom boolean flag when the surrounding framework already uses tokens.

The Web API guide includes an async route handler and a streaming handler. The IoT monitor consumes a cancellable telemetry stream.