Skip to content

Commit 302a680

Browse files
authored
Vineeth/force rollback (plastic-labs#486)
* fix: Explicit Rollback in Transaction * chore: update tests
1 parent 29ff465 commit 302a680

10 files changed

Lines changed: 33 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [3.0.5] - 2026-04-03
9+
10+
### Fixed
11+
12+
- explicit rollback on all transactions to force connection closed
13+
814
## [3.0.4] - 2026-04-02
915

1016
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
---
1010

11-
![Static Badge](https://img.shields.io/badge/Version-3.0.4-blue)
11+
![Static Badge](https://img.shields.io/badge/Version-3.0.5-blue)
1212
[![PyPI version](https://img.shields.io/pypi/v/honcho-ai.svg)](https://pypi.org/project/honcho-ai/)
1313
[![NPM version](https://img.shields.io/npm/v/@honcho-ai/sdk.svg)](https://npmjs.org/package/@honcho-ai/sdk)
1414
[![Discord](https://img.shields.io/discord/1016845111637839922?style=flat&logo=discord&logoColor=23ffffff&label=Plastic%20Labs&labelColor=235865F2)](https://discord.gg/plasticlabs)

docs/changelog/compatibility-guide.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ This guide helps you match the right SDK version to your Honcho API version. New
3030

3131
| Honcho API Version | TypeScript SDK | Python SDK |
3232
|-------------------|---------------|------------|
33-
| v3.0.4 (Current) | v2.1.0 | v2.1.0 |
33+
| v3.0.5 (Current) | v2.1.0 | v2.1.0 |
34+
| v3.0.4 | v2.1.0 | v2.1.0 |
3435
| v3.0.3 | v2.1.0 | v2.1.0 |
3536
| v3.0.2 | v2.0.0+ | v2.0.0+ |
3637
| v3.0.1 | v2.0.0+ | v2.0.0+ |

docs/changelog/introduction.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ Welcome to the Honcho changelog! This section documents all notable changes to t
2727
### Honcho API and SDK Changelogs
2828
<Tabs>
2929
<Tab title="Honcho API">
30-
<Update label="v3.0.4 (Current)">
30+
<Update label="v3.0.5 (Current)">
31+
### Fixed
32+
33+
- explicit rollback on all transactions to force connection closed
34+
</Update>
35+
36+
<Update label="v3.0.4">
3137
### Added
3238

3339
- JSONB metadata validation enforces 100 key limit and max depth of 5 (#419)

docs/docs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"navigation": {
3030
"versions": [
3131
{
32-
"version": "v3.0.4",
32+
"version": "v3.0.5",
3333
"api": {
3434
"openapi": [
3535
"v3/openapi.json"

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "honcho"
3-
version = "3.0.4"
3+
version = "3.0.5"
44
description = "Honcho Server"
55
authors = [
66
{name = "Plastic Labs", email = "hello@plasticlabs.ai"},

src/dependencies.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ async def get_db():
2626
await db.rollback()
2727
raise
2828
finally:
29-
if db.in_transaction():
30-
await db.rollback()
29+
# Always send ROLLBACK unconditionally so the wire-level transaction
30+
# is closed before the TCP connection drops. Supavisor v2 does NOT
31+
# clean up orphaned transactions on client disconnect in transaction-
32+
# pooling mode, so relying on `in_transaction()` (Python-side state)
33+
# can leave the backend pinned with an open BEGIN.
34+
await db.rollback()
3135
await db.close()
3236

3337

@@ -57,8 +61,8 @@ async def tracked_db(operation_name: str | None = None):
5761
await db.rollback()
5862
raise
5963
finally:
60-
if db.in_transaction():
61-
await db.rollback()
64+
# Always send ROLLBACK unconditionally — see get_db() comment.
65+
await db.rollback()
6266
await db.close()
6367
if token: # Only reset if we set it
6468
request_context.reset(token)

src/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ async def lifespan(_: FastAPI):
154154
title="Honcho API",
155155
summary="The Identity Layer for the Agentic World",
156156
description="""Honcho is a platform for giving agents user-centric memory and social cognition.""",
157-
version="3.0.4",
157+
version="3.0.5",
158158
contact={
159159
"name": "Plastic Labs",
160160
"url": "https://honcho.dev",

tests/test_dependencies.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async def test_get_db_sets_application_name_when_tracing_enabled(
5252
await dep_gen.aclose()
5353
request_context.reset(context_token)
5454

55-
assert fake_db.rollback_calls == 0
55+
assert fake_db.rollback_calls == 1 # unconditional rollback in finally
5656
assert fake_db.close_calls == 1
5757

5858

@@ -70,7 +70,7 @@ async def test_get_db_rolls_back_and_closes_when_consumer_raises(
7070
with pytest.raises(RuntimeError, match="boom"):
7171
await dep_gen.athrow(RuntimeError("boom"))
7272

73-
assert fake_db.rollback_calls == 1
73+
assert fake_db.rollback_calls == 2 # once in except, once in finally
7474
assert fake_db.close_calls == 1
7575

7676

@@ -99,7 +99,7 @@ async def test_tracked_db_creates_and_resets_task_context(
9999
stmt, params = fake_db.execute_calls[0]
100100
assert "set_config" in str(stmt)
101101
assert params == {"name": "task:cleanup_job:12345678"}
102-
assert fake_db.rollback_calls == 0
102+
assert fake_db.rollback_calls == 1 # unconditional rollback in finally
103103
assert fake_db.close_calls == 1
104104

105105

@@ -122,7 +122,7 @@ async def test_tracked_db_preserves_existing_request_context(
122122
stmt, params = fake_db.execute_calls[0]
123123
assert "set_config" in str(stmt)
124124
assert params == {"name": "request:existing"}
125-
assert fake_db.rollback_calls == 0
125+
assert fake_db.rollback_calls == 1 # unconditional rollback in finally
126126
assert fake_db.close_calls == 1
127127

128128

@@ -138,7 +138,7 @@ async def test_tracked_db_rolls_back_on_error_and_closes(
138138
async with real_tracked_db("operation"):
139139
raise ValueError("failed operation")
140140

141-
assert fake_db.rollback_calls == 1
141+
assert fake_db.rollback_calls == 2 # once in except, once in finally
142142
assert fake_db.close_calls == 1
143143

144144

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)