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
42 changes: 42 additions & 0 deletions docs/examples/faststream.rst
Comment thread
birthdaysgift marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.. _faststream-example:

FastStream example
==================

.. meta::
:keywords: Python,Dependency Injection,FastStream,Example
:description: This example demonstrates a usage of FastStream with Dependency Injector.


This example shows how to use ``Dependency Injector`` with `FastStream <https://github.com/ag2ai/faststream>`_.

The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/faststream>`_.

Despite ``FastStream`` uses ``FastDepends`` library for dependency injection, the integration between
``Dependency injector`` and ``FastStream`` has a small difference from already existing :ref:`fastdepends-example`.

Since ``FastStream`` also leverages function signatures to determine input data types you have to use ``Depends()`` function
with ``cast=False`` argument to make ``FastStream`` ignore your injected dependency argument in the function signature.

Example below shows how to inject ``Counter`` class into ``FastStream`` redis handler so that it will distinguish between
message schema (``User``) and injected dependency (``Counter``) and use them both correctly.

Listing of ``consumer.py``:

.. literalinclude:: ../../examples/miniapps/faststream/consumer.py
:language: python

Listing of ``producer.py``:

.. literalinclude:: ../../examples/miniapps/faststream/producer.py
:language: python

Sources
-------

Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/faststream>`_.

.. include:: ../sponsor.rst

.. disqus::

1 change: 1 addition & 0 deletions docs/examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ Explore the examples to see the ``Dependency Injector`` in action.
fastapi-redis
fastapi-sqlalchemy
fastdepends
faststream

.. disqus::
10 changes: 10 additions & 0 deletions examples/miniapps/faststream/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.13-bookworm

WORKDIR /app

COPY requirements.txt ./
RUN pip install -r requirements.txt

COPY . ./

ENV PYTHONUNBUFFERED=1
41 changes: 41 additions & 0 deletions examples/miniapps/faststream/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
FastStream + Dependency Injector Example
========================================

This is a `FastStream <https://github.com/ag2ai/faststream>`_ +
`Dependency Injector <https://python-dependency-injector.ets-labs.org/>`_ example application.

The example application is a simple consumer that counts messages sent to redis channel by producer.

Counter is provided to faststream handler as a dependency injected by ``dependency_injector`` library.

Run
---

Everything can be run via docker compose.

A convenient ``run.sh`` script runs consumer, producer and redis services, prints logs from consumer
and shuts down once producer exits.


Run the sciprt:

.. code-block:: bash

./run.sh

The output should be something like:

.. code-block::

faststream-example-consumer | Message #1 from John: 'As you can see'
faststream-example-consumer | Message #2 from John: 'messages are counted correctly'
faststream-example-consumer | Message #3 from John: 'by the counter that is injected'
faststream-example-consumer | Message #4 from John: 'into faststream handler'
faststream-example-consumer | Message #5 from John: 'via awesome dependency_injector library.'


Once you've done working with this example you can clean up docker images and containers it produced:

.. code-block:: bash

docker compose down --rmi local
67 changes: 67 additions & 0 deletions examples/miniapps/faststream/consumer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import asyncio
from typing import Annotated

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
from faststream import Depends, FastStream
from faststream.redis import RedisBroker, RedisRouter
from pydantic import BaseModel


class Counter:
def __init__(self):
self.count = 0

def next(self) -> int:
self.count += 1
return self.count


class Container(containers.DeclarativeContainer):
counter = providers.Singleton(Counter)

config = providers.Configuration()

broker = providers.Singleton(RedisBroker, config.redis_url, logger=None)
app = providers.Factory(FastStream, broker, logger=None)


class Message(BaseModel):
user: str
text: str


router = RedisRouter()


@router.subscriber("messages")
@inject
async def handle_user_message(
message: Message,
counter: Annotated[
Counter,
Depends(
Provide[Container.counter],
cast=False, # <-- this is the key part
),
],
) -> None:
count = counter.next()
print(f"Message #{count} from {message.user}: '{message.text}'")


async def main() -> None:
container = Container()
container.wire(modules=[__name__])

container.config.redis_url.from_env("REDIS_URL")

broker = container.broker()
broker.include_router(router)

app = container.app()
await app.run()


if __name__ == "__main__":
asyncio.run(main())
24 changes: 24 additions & 0 deletions examples/miniapps/faststream/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: faststream-example

services:

redis:
image: redis

consumer:
build: .
environment:
REDIS_URL: "redis://redis"
depends_on:
- redis
entrypoint: python3 consumer.py

producer:
build: .
environment:
REDIS_HOST: "redis"
REDIS_PORT: "6379"
depends_on:
- consumer
entrypoint: python3 producer.py

37 changes: 37 additions & 0 deletions examples/miniapps/faststream/producer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import json
import time

from dependency_injector import containers, providers
from redis import Redis


class Container(containers.DeclarativeContainer):
config = providers.Configuration()

redis = providers.Singleton(Redis, config.redis_host, config.redis_port.as_int())


def main():
container = Container()
container.wire(modules=[__name__])

container.config.redis_host.from_env("REDIS_HOST")
container.config.redis_port.from_env("REDIS_PORT")

redis = container.redis()

for text in (
"As you can see",
"messages are counted correctly",
"by the counter that is injected",
"into faststream handler",
"via awesome dependency_injector library.",
):
time.sleep(2)

message = {"user": "John", "text": text}
redis.publish("messages", json.dumps(message))


if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions examples/miniapps/faststream/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependency_injector
faststream
pydantic
redis
7 changes: 7 additions & 0 deletions examples/miniapps/faststream/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

Comment thread
birthdaysgift marked this conversation as resolved.
docker compose up \
--no-attach=redis \
--abort-on-container-exit \
--exit-code-from producer