Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
python:
- "3.11"
- "3.12"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not 3.12? It feels weird to skip a version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't wanna wait for three CI runs in each PR :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll only wait for one. All are only tested in the merge queue and pushes.

- "3.13"
nox-session:
# To speed things up a bit we use the special ci_checks_max session
# that uses the same venv to run multiple linting sessions
Expand Down Expand Up @@ -113,6 +114,7 @@ jobs:
python:
- "3.11"
- "3.12"
- "3.13"
runs-on: ${{ matrix.os }}${{ matrix.arch != 'amd64' && format('-{0}', matrix.arch) || '' }}

steps:
Expand Down
123 changes: 106 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,119 @@

## Introduction

A highlevel interface for the dispatch API.
The `frequenz-dispatch` library provides a high-level Python interface for
interacting with the Frequenz Dispatch API. This library enables you to
manage and monitor dispatch operations in microgrids, including lifecycle
events and running status changes of dispatch operations.

See [the documentation](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch) for more information.
The main entry point is the [`Dispatcher`][dispatcher-class] class, which
provides methods for receiving dispatch lifecycle events and running status
updates, allowing you to build reactive applications that respond to dispatch
state changes.

## Usage
## Supported Platforms

The following platforms are officially supported (tested):

- **Python:** 3.11, 3.13
- **Operating System:** Ubuntu Linux 24.04
- **Architectures:** amd64, arm64

The [`Dispatcher` class](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher), the main entry point for the API, provides two channels:
## Installation

* [Lifecycle events](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.lifecycle_events): A channel that sends a message whenever a [Dispatch][frequenz.dispatch.Dispatch] is created, updated or deleted.
* [Running status change](https://frequenz-floss.github.io/frequenz-dispatch-python/v0.1/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.running_status_change): Sends a dispatch message whenever a dispatch is ready to be executed according to the schedule or the running status of the dispatch changed in a way that could potentially require the actor to start, stop or reconfigure itself.
### Using pip

### Example using the running status change channel
You can install the package from PyPI:

```bash
python3 -m pip install frequenz-dispatch
```

### Using pyproject.toml

Add the dependency to your `pyproject.toml` file:

```toml
[project]
dependencies = [
"frequenz-dispatch >= 1.0.1, < 2",
]
```

> [!NOTE]
> We recommend pinning the dependency to the latest version for programs,
> like `"frequenz-dispatch == 1.0.1"`, and specifying a version range
> spanning one major version for libraries, like
> `"frequenz-dispatch >= 1.0.1, < 2"`. We follow [semver](https://semver.org/).

## Quick Start

Here's a minimal example to get you started with lifecycle events:

```python
import asyncio
import os

from frequenz.dispatch import Created, Deleted, Dispatcher, Updated

async def main() -> None:
url = os.getenv("DISPATCH_API_URL", "grpc://localhost:50051")
auth_key = os.getenv("DISPATCH_API_AUTH_KEY", "my-api-key")
sign_secret = os.getenv("DISPATCH_API_SIGN_SECRET")
microgrid_id = 1

async with Dispatcher(
microgrid_id=microgrid_id,
server_url=url,
auth_key=auth_key,
sign_secret=sign_secret,
) as dispatcher:
events_receiver = dispatcher.new_lifecycle_events_receiver("MY_TYPE")

async for event in events_receiver:
match event:
case Created(dispatch):
print(f"Created: {dispatch}")
case Updated(dispatch):
print(f"Updated: {dispatch}")
case Deleted(dispatch):
print(f"Deleted: {dispatch}")

asyncio.run(main())
```

The [`Dispatcher` class][dispatcher-class] provides two receiver methods:

* [`new_lifecycle_events_receiver()`][lifecycle-events]: Returns a receiver
that sends a message whenever a Dispatch is created, updated or deleted.
* [`new_running_state_event_receiver()`][running-status-change]: Returns a
receiver that sends a dispatch message whenever a dispatch is ready to be
executed according to the schedule or the running status of the dispatch
changed in a way that could potentially require the actor to start, stop or
reconfigure itself.

### Example managing actors with dispatch events

```python
import os
from unittest.mock import MagicMock
from datetime import timedelta
from unittest.mock import MagicMock

from frequenz.channels import Receiver
from frequenz.sdk.actor import Actor

from frequenz.dispatch import Dispatcher, DispatchInfo, MergeByType

async def create_actor(dispatch: DispatchInfo, receiver: Receiver[DispatchInfo]) -> Actor:
async def create_actor(
dispatch: DispatchInfo, receiver: Receiver[DispatchInfo]
) -> Actor:
return MagicMock(dispatch=dispatch, receiver=receiver)

async def run():
url = os.getenv("DISPATCH_API_URL", "grpc://dispatch.url.goes.here.example.com")
auth_key = os.getenv("DISPATCH_API_AUTH_KEY", "some-key")
async def run() -> None:
url = os.getenv(
"DISPATCH_API_URL", "grpc://dispatch.api.example.com:50051"
)
auth_key = os.getenv("DISPATCH_API_AUTH_KEY", "my-api-key")
sign_secret = os.getenv("DISPATCH_API_SIGN_SECRET")

microgrid_id = 1
Expand All @@ -52,13 +139,15 @@ async def run():
await dispatcher
```

## Supported Platforms
## Documentation

The following platforms are officially supported (tested):
For complete API documentation, examples, and advanced usage patterns, see
[the documentation][docs].

- **Python:** 3.11
- **Operating System:** Ubuntu Linux 20.04
- **Architectures:** amd64, arm64
[dispatcher-class]: https://frequenz-floss.github.io/frequenz-dispatch-python/latest/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher
[lifecycle-events]: https://frequenz-floss.github.io/frequenz-dispatch-python/latest/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.new_lifecycle_events_receiver
[running-status-change]: https://frequenz-floss.github.io/frequenz-dispatch-python/latest/reference/frequenz/dispatch/#frequenz.dispatch.Dispatcher.new_running_state_event_receiver
[docs]: https://frequenz-floss.github.io/frequenz-dispatch-python/latest/

## Contributing

Expand Down