Skip to content

Publishing with metadata

Metadata is free-form data carried alongside a call, in envelope.metadata, for example a trace id or the source of the request. Attach it with with_metadata:

"""Publishing a task call with metadata attached to its envelope."""

import asyncio

from asynk import App, Envelope, PublishOptions


class PrintingProducer:
    """A producer that prints each envelope's metadata instead of sending it."""

    async def publish(
        self, envelope: Envelope, body: bytes, options: PublishOptions | None = None
    ) -> str:
        print(envelope.task, envelope.metadata)
        return envelope.id


app = App("metadata", producer=PrintingProducer())


@app.task()
async def add(a: int, b: int) -> int:
    return a + b


async def main() -> None:
    await add.with_metadata(source="api").delay(1, b=2)

    # Each call returns a new bound task; later keys override earlier ones.
    traced = add.with_metadata(source="api", trace="x")
    await traced.with_metadata(trace="y").delay(1, b=2)


if __name__ == "__main__":
    asyncio.run(main())

with_metadata returns an immutable bound task, so calls can be chained and later keys override earlier ones; the task itself is unchanged. The bound task has the same type-checked delay as the task. Metadata values go through the app's codec with the rest of the envelope, so they must be values it can encode.

The scheduler uses metadata too: each scheduled publish carries idempotency_key and scheduled_at.