Documentation / Guides / PostgreSQL
Publish terminal results to PostgreSQL¶
Result publication happens after Closure. A slow or failed database cannot delay or rewrite the completed call.
Install and migrate¶
Apply the packaged migration under your deployment's normal migration control:
src/vaani/publishers/migrations/postgres/v1.sqlsrc/vaani/publishers/migrations/postgres/manifest.json
Do not let the bot process create or mutate schemas at call time.
Create a canonical publication¶
from datetime import UTC, datetime
from vaani import DeliveryPolicy, ResultPublicationRecord
from vaani.publishers.postgres import (
PostgresPublisherConfig,
PostgresResultPublisher,
)
record = ResultPublicationRecord(
idempotency_key=f"call-result:{result.call_id}",
call_id=result.call_id,
result_schema_version=result.provenance.result_schema_version,
result_digest=result.result_digest(),
canonical_result_bytes=result.canonical_bytes(),
published_at=datetime.now(UTC),
)
publisher = PostgresResultPublisher(
PostgresPublisherConfig(
sink_id="analytics-primary",
table_name="vaani_call_results",
credential_source=database_credentials,
)
)
report = await publisher.publish(
record,
DeliveryPolicy(timeout_seconds=30, max_attempts=2),
)
The credential source may resolve an explicit SQLAlchemy-compatible PostgreSQL
URL (for example from a consumer-owned DATABASE_URL) or a supported backend.
VAANI itself does not read DATABASE_URL.
Idempotency and uncertainty¶
Reuse the same idempotency key for the same canonical bytes. A conflicting
digest/bytes pair returns CONFLICT; it must not overwrite prior evidence.
Timeout or an unknown commit outcome is not permission to manufacture a success
record.
DeliveryReport is separate from CallResult and normalizes success, failure,
timeout, cancellation, or conflict. Send publisher metrics to operations
without embedding database diagnostics or credentials in call evidence.
Live PostgreSQL credentials are deferred in the current environment; no live publication success is claimed.