Metadata-Version: 2.1
Name: taskiq-fastapi
Version: 0.1.0
Summary: FastAPI integration for taskiq
License: LICENSE
Keywords: taskiq,tasks,distributed,async,fastapi
Author: Taskiq team
Author-email: taskiq@no-reply.com
Maintainer: Taskiq team
Maintainer-email: taskiq@no-reply.com
Requires-Python: >=3.7,<4.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: System :: Networking
Classifier: Typing :: Typed
Requires-Dist: fastapi
Requires-Dist: taskiq (>=0.3.1,<1)
Description-Content-Type: text/markdown

# Taskiq + FastAPI

This repository has a code to integrate FastAPI with taskiq easily.

Taskiq and FastAPI both have dependencies and this library makes it possible to depend on
`fastapi.Request` or `starlette.requests.HTTPConnection` in taskiq tasks.

With this library you can easily re-use your fastapi dependencies in taskiq functions.

## How does it work?

It adds startup functions to broker so it imports your fastapi application
and creates a single worker-wide Request and HTTPConnection objects that you depend on.

THIS REQUEST IS NOT RELATED TO THE ACTUAL REQUESTS IN FASTAPI!
This request won't have actual data about the request you were handling while sending task.

## Usage

Here we have an example of function that is being used by both taskiq's task and
fastapi's handler function.

I have a script called `test_script.py` so my app can be found at `test_script:app`.
We use strings to resolve application to bypass circular imports.

```python
from fastapi import FastAPI, Request
from pydantic import BaseModel
from redis.asyncio import ConnectionPool, Redis
from fastapi import Depends as FastAPIDepends
from taskiq import TaskiqDepends
import taskiq_fastapi
from taskiq import ZeroMQBroker

broker = ZeroMQBroker()

app = FastAPI()


@app.on_event("startup")
async def app_startup():
    #####################
    # IMPORTANT NOTE    #
    #####################
    # If you won't check that this is not
    # a worker process, you'll
    # create an infinite recursion. Because in worker processes
    # fastapi startup will be called.
    if not broker.is_worker_process:
        print("Starting broker")
        await broker.startup()
    print("Creating redis pool")
    app.state.redis_pool = ConnectionPool.from_url("redis://localhost")


@app.on_event("shutdown")
async def app_shutdown():
    #####################
    # IMPORTANT NOTE    #
    #####################
    # If you won't check that this is not
    # a worker process, you'll
    # create an infinite recursion. Because in worker processes
    # fastapi startup will be called.
    if not broker.is_worker_process:
        print("Shutting down broker")
        await broker.shutdown()
    print("Stopping redis pool")
    await app.state.redis_pool.disconnect()


# Here we call our magic function.
taskiq_fastapi.init(broker, "test_script:app")


def get_redis_pool(request: Request = TaskiqDepends()) -> ConnectionPool:
    return request.app.state.redis_pool


@broker.task
async def my_redis_task(
    key: str,
    val: str,
    pool: ConnectionPool = TaskiqDepends(get_redis_pool),
):
    async with Redis(connection_pool=pool) as redis:
        await redis.set(key, val)
        print("Value set.")


class MyVal(BaseModel):
    key: str
    val: str


@app.post("/val")
async def setval_endpoint(val: MyVal) -> None:
    await my_redis_task.kiq(
        key=val.key,
        val=val.val,
    )
    print("Task sent")


@app.get("/val")
async def getval_endpoint(
    key: str,
    pool: ConnectionPool = FastAPIDepends(get_redis_pool),
) -> str:
    async with Redis(connection_pool=pool, decode_responses=True) as redis:
        return await redis.get(key)

```

