Documentation (#311)

* Fix & update asyncloop documentation

* Add cancellation documentation

* Add documentation generation workflow

* pin nim version for doc gen

* update readme

* fix example

* Simplify examples
This commit is contained in:
Tanguy 2023-02-16 21:27:31 +01:00 committed by GitHub
parent 1e743dc415
commit a50ac4f642
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 134 additions and 35 deletions

62
.github/workflows/doc.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: Docgen
on:
push:
branches:
- master
- docs
workflow_dispatch:
jobs:
build:
timeout-minutes: 20
name: 'Generate & upload documentation'
runs-on: 'ubuntu-latest'
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: '1.6.6'
- name: Generate doc
run: |
nim --version
nimble --version
nimble install -dy
# nim doc can "fail", but the doc is still generated
nim doc --git.url:https://github.com/status-im/nim-chronos --git.commit:master --outdir:docs --project chronos || true
# check that the folder exists
ls docs
- name: Clone the gh-pages branch
uses: actions/checkout@v2
with:
repository: status-im/nim-chronos
ref: gh-pages
path: subdoc
submodules: true
fetch-depth: 0
- name: Commit & push
run: |
cd subdoc
# Update / create this branch doc
rm -rf docs
mv ../docs .
# Remove .idx files
# NOTE: git also uses idx files in his
# internal folder, hence the `*` instead of `.`
find * -name "*.idx" -delete
git add .
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
git config --global user.name = "${{ github.actor }}"
git commit -a -m "update docs"
git push origin gh-pages

View File

@ -1,7 +1,6 @@
# Chronos - An efficient library for asynchronous programming
[![Github action](https://github.com/status-im/nim-chronos/workflows/nim-chronos%20CI/badge.svg)](https://github.com/status-im/nim-chronos/actions/workflows/ci.yml)
[![Windows build status (AppVeyor)](https://img.shields.io/appveyor/ci/nimbus/nim-asyncdispatch2/master.svg?label=Windows "Windows build status (Appveyor)")](https://ci.appveyor.com/project/nimbus/nim-asyncdispatch2)
[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
![Stability: experimental](https://img.shields.io/badge/stability-experimental-orange.svg)
@ -22,7 +21,7 @@ Chronos is an efficient [async/await](https://en.wikipedia.org/wiki/Async/await)
You can use Nim's official package manager Nimble to install Chronos:
```text
nimble install https://github.com/status-im/nim-chronos.git
nimble install chronos
```
or add a dependency to your `.nimble` file:
@ -245,6 +244,68 @@ In the strict mode, `async` functions are checked such that they only raise
effects on forward declarations, callbacks and methods using
`{.raises: [CatchableError].}` (or more strict) annotations.
### Cancellation support
Any running `Future` can be cancelled. This can be used to launch multiple
futures, and wait for one of them to finish, and cancel the rest of them,
to add timeout, or to let the user cancel a running task.
```nim
# Simple cancellation
let future = sleepAsync(10.minutes)
future.cancel()
# Wait for cancellation
let future2 = sleepAsync(10.minutes)
await future2.cancelAndWait()
# Race between futures
proc retrievePage(uri: string): Future[string] {.async.} =
# requires to import uri, chronos/apps/http/httpclient, stew/byteutils
let httpSession = HttpSessionRef.new()
try:
resp = await httpSession.fetch(parseUri(uri))
result = string.fromBytes(resp.data)
finally:
# be sure to always close the session
await httpSession.closeWait()
let
futs =
@[
retrievePage("https://duckduckgo.com/?q=chronos"),
retrievePage("https://www.google.fr/search?q=chronos")
]
let finishedFut = await one(futs)
for fut in futs:
if not fut.finished:
fut.cancel()
echo "Result: ", await finishedFut
```
When an `await` is cancelled, it will raise a `CancelledError`:
```nim
proc c1 {.async.} =
echo "Before sleep"
try:
await sleepAsync(10.minutes)
echo "After sleep" # not reach due to cancellation
except CancelledError as exc:
echo "We got cancelled!"
raise exc
proc c2 {.async.} =
await c1()
echo "Never reached, since the CancelledError got re-raised"
let work = c2()
waitFor(work.cancelAndWait())
```
The `CancelledError` will now travel up the stack like any other exception.
It can be caught and handled (for instance, freeing some resources)
### Multiple async backend support
Thanks to its powerful macro support, Nim allows `async`/`await` to be

View File

@ -22,7 +22,7 @@ export timer
#{.injectStmt: newGcInvariant().}
## AsyncDispatch
## Chronos
## *************
##
## This module implements asynchronous IO. This includes a dispatcher,
@ -112,57 +112,33 @@ export timer
## ``await socket.send("foobar")``.
##
## If an awaited future completes with an error, then ``await`` will re-raise
## this error. To avoid this, you can use the ``yield`` keyword instead of
## ``await``. The following section shows different ways that you can handle
## exceptions in async procs.
## this error.
##
## Handling Exceptions
## ~~~~~~~~~~~~~~~~~~~
## -------------------
##
## The most reliable way to handle exceptions is to use ``yield`` on a future
## then check the future's ``failed`` property. For example:
##
## .. code-block:: Nim
## var future = sock.recv(100)
## yield future
## if future.failed:
## # Handle exception
##
## The ``async`` procedures also offer limited support for the try statement.
## The ``async`` procedures also offer support for the try statement.
##
## .. code-block:: Nim
## try:
## let data = await sock.recv(100)
## echo("Received ", data)
## except:
## # Handle exception
##
## Unfortunately the semantics of the try statement may not always be correct,
## and occasionally the compilation may fail altogether.
## As such it is better to use the former style when possible.
##
## except CancelledError as exc:
## # Handle exc
##
## Discarding futures
## ------------------
##
## Futures should **never** be discarded. This is because they may contain
## errors. If you do not care for the result of a Future then you should
## use the ``asyncCheck`` procedure instead of the ``discard`` keyword.
##
## Examples
## --------
##
## For examples take a look at the documentation for the modules implementing
## asynchronous IO. A good place to start is the
## `asyncnet module <asyncnet.html>`_.
## use the ``asyncSpawn`` procedure instead of the ``discard`` keyword.
## ``asyncSpawn`` will transform any exception thrown by the called procedure
## to a Defect
##
## Limitations/Bugs
## ----------------
##
## * The effect system (``raises: []``) does not work with async procedures.
## * Can't await in a ``except`` body
## * Forward declarations for async procs are broken,
## link includes workaround: https://github.com/nim-lang/Nim/issues/3182.
# TODO: Check if yielded future is nil and throw a more meaningful exception