Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 1.2.2 instead.
Reason given by maintainers: No executionStatus and miscounts rejected events. Use the latest version.

aforo-grpc-metering

Meter every gRPC call with a server interceptor — one Aforo event per RPC, with the gRPC status mapped to a readable label, call type, and duration. Streaming RPCs are metered with one explicit record() call.

Version: 1.0.0 · Apache-2.0 · Changelog · User guide

Install

Intended public install:

pip install aforo-grpc-metering
pip install "aforo-grpc-metering[httpx]"     # or [aiohttp] — faster HTTP flush than stdlib urllib

Not yet on PyPI — install from source for now:

git clone https://github.com/aforoai/SDKs.git
cd SDKs/aforo-metering-sdks/python-grpc     # folder holding setup.py
pip install -e .
pip install -e ".[httpx]"              # or [aiohttp]

The one required dependency is grpcio>=1.50.

Quickstart — unary interceptor

Best when your service is mostly unary RPCs and you want per-call billing with no handler changes.

import os, grpc
from concurrent import futures
from aforo_grpc_metering import AforoGrpcBilling, AforoGrpcInterceptor

billing = AforoGrpcBilling(
    tenant_id="tenant_acme",
    product_id="prod_grpc_user_svc",
    api_key=os.environ["AFORO_API_KEY"],
    ingestor_url="https://api.aforo.ai",
    service_name="acme.v1.UserService",
)

server = grpc.server(
    futures.ThreadPoolExecutor(max_workers=10),
    interceptors=[AforoGrpcInterceptor(billing)],
)
# add_UserServiceServicer_to_server(servicer, server)
server.add_insecure_port("[::]:50051")
server.start()
server.wait_for_termination()

Every unary RPC is now metered — one grpc_api.rpc_calls event with grpcStatusCode, grpcCallType=UNARY, and executionDurationMs, POSTed to https://api.aforo.ai/v1/ingest/batch with X-API-Key: <api_key> and X-Tenant-Id: <tenant_id>.

⚠ Events are sent to the ingestor's /v1/ingest/batch path as {"events": [...]}, at most 1000 events per request (larger buffers are split). Set ingestor_url to the host only — the SDK appends the path.

The interceptor auto-wraps unary RPCs only. For server-stream / client-stream / bidi, call billing.record(...) yourself at the end of the handler (see the user guide). tenant_id is fixed from config; the default extractor reads x-customer-id from invocation metadata, and calls with no resolvable customer ID are not metered.

Configuration

Constructor arguments for AforoGrpcBilling(...):

Option Type Default What it does
tenant_id str — (required) Aforo tenant; sent as X-Tenant-Id.
product_id str — (required) Product the RPCs bill against.
api_key str — (required) Aforo API key, sent to the ingestor as X-API-Key.
ingestor_url str — (required) Host; /v1/ingest/batch is appended.
service_name str — (required) Fully-qualified gRPC service; stamped as grpcService.
flush_interval_sec float 5.0 Background flush cadence (daemon thread from construction).
flush_count int 50 Buffer size that triggers an immediate flush.
on_error Callable[[Exception], None]? logs Called on permanent batch failure, and with the ingestor's errors[].message when it rejects events.
product_type str "GRPC_API" Top-level productType sent on every event (trimmed and upper-cased; values the SDK does not know are passed through). Override per event with record(..., product_type=...).
customer_id_extractor Callable[[Any], str?]? reads x-customer-id from metadata Resolve the billed customer from the gRPC context.

Status mapping: GRPC_STATUS_LABELS maps numeric codes to descriptor labels (e.g. OK, NOT_FOUND, UNAVAILABLE); the interceptor records the label as grpcStatusCode. Retry is fixed at 3 attempts (1s / 2s backoff between them); 408 and 5xx are retried, 429 waits for Retry-After (capped at 60 s), and any other 4xx is not retried.

Walk me through it

Install → add the interceptor → call an RPC → confirm the event in Aforo, plus the streaming pattern, is in USER_GUIDE.md.

What this doesn't cover

The interceptor only auto-meters unary RPCs — streaming RPCs need a manual record() (the SDK can't know when a stream ends or how many messages flowed). It meters per-call, not per-message, unless you pass message_count/data_bytes to record(). It doesn't enforce quotas or abort RPCs. Pricing and metric mapping live in the Aforo console.

Metadata

Release files for aforo-grpc-metering 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aforo-grpc-metering 1.0.0
File Size Uploaded
aforo_grpc_metering-1.0.0.tar.gz 16.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aforo-grpc-metering 1.0.0
File Interpreter ABI Platform
aforo_grpc_metering-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 26.2 kB

Release files / aforo_grpc_metering-1.0.0.tar.gz

Download URL aforo_grpc_metering-1.0.0.tar.gz
Size 16.7 kB
Tags Source
SHA-256 checksum
How to use checksums
45aa3559c9b0fcb5609d7e5b0a84db0aabfd04d182b295f7bb4499c67183dd9c
BLAKE2b-256 checksum
How to use checksums
0fcd61b5ee56a0521f2df20b07e16b741511c82b14cce12ef5d9eb447191f108
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / aforo_grpc_metering-1.0.0-py3-none-any.whl

Download URL aforo_grpc_metering-1.0.0-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4ee4cabd6d2736e375a33547c0d017b5b02ae2d6edbefb57012a0823bfc84e95
BLAKE2b-256 checksum
How to use checksums
cf36324ea61bb620f1ac2d75d594d4a1899459a687e571a8d50256dd3ce38326
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.2

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page