Skip to content

community[minor]: Add native async support to SQLChatMessageHistory #22065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
Jun 5, 2024

Conversation

pprados
Copy link
Contributor

@pprados pprados commented May 23, 2024

package community: Fix SQLChatMessageHistory

Description

Here is a rewrite of SQLChatMessageHistory to properly implement the asynchronous approach. The code circumvents issue 22021 by accepting a synchronous call to def add_messages() in an asynchronous scenario. This bypasses the bug.

For the same reasons as in PR 22 of langchain-postgres, we use a lazy strategy for table creation. Indeed, the promise of the constructor cannot be fulfilled without this. It is not possible to invoke a synchronous call in a constructor. We compensate for this by waiting for the next asynchronous method call to create the table.

The goal of the PostgresChatMessageHistory class (in langchain-postgres) is, among other things, to be able to recycle database connections. The implementation of the class is problematic, as we have demonstrated in issue 22021.

Our new implementation of SQLChatMessageHistory achieves this by using a singleton of type (Async)Engine for the database connection. The connection pool is managed by this singleton, and the code is then reentrant.

We also accept the type str (optionally complemented by async_mode. I know you don't like this much, but it's the only way to allow an asynchronous connection string).

In order to unify the different classes handling database connections, we have renamed connection_string to connection, and Session to session_maker.

Now, a single transaction is used to add a list of messages. Thus, a crash during this write operation will not leave the database in an unstable state with a partially added message list. This makes the code resilient.

We believe that the PostgresChatMessageHistory class is no longer necessary and can be replaced by:

PostgresChatMessageHistory = SQLChatMessageHistory

This also fixes the bug.

Issue

  • issue 22021
    • Bug in _exit_history()
    • Bugs in PostgresChatMessageHistory and sync usage
    • Bugs in PostgresChatMessageHistory and async usage
  • issue 36

Twitter handle:

pprados

Tests

  • libs/community/tests/unit_tests/chat_message_histories/test_sql.py (add async test)

@baskaryan, @eyurtsev or @hwchase17 can you check this PR ?
And, I've been waiting a long time for validation from other PRs. Can you take a look?

Copy link

vercel bot commented May 23, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
langchain ⬜️ Ignored (Inspect) Visit Preview Jun 5, 2024 3:06pm

Copy link
Collaborator

@eyurtsev eyurtsev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost ready for merging.

Most important things to address:

  1. Undo changes in core
  2. Undo the code that calls async code from a sync function using a new event loop
  3. Create a separate async session maker in chat history, so we can consolidate the asserts in just two places

@eyurtsev eyurtsev self-assigned this May 23, 2024
@pprados pprados marked this pull request as ready for review May 23, 2024 17:44
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. 🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature labels May 23, 2024
@pprados pprados marked this pull request as draft May 24, 2024 07:59
@pprados pprados marked this pull request as ready for review May 24, 2024 08:54
@eyurtsev
Copy link
Collaborator

eyurtsev commented Jun 4, 2024

@pprados back from vacation -- this looks ready to merge, I'll take a final look tomorrow and resolve merge conflict

table_name: str = "message_store",
session_id_field_name: str = "session_id",
custom_message_converter: Optional[BaseMessageConverter] = None,
connection: Union[None, DBConnection] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(unrelated to this PR)


@pprados this pattern could be useful if you needed a transaction (e.g., as was the case in the indexing API if I recall correctly)

Allows passing a session maker as part of the init instead of initializing and then mutating a class attribute (the latter pattern is more likely to break in threaded scenarios)

@dosubot dosubot bot added the lgtm PR looks good. Use to confirm that a PR is ready for merging. label Jun 5, 2024
@eyurtsev eyurtsev changed the title Real async version of SQLChatMessageHistory community[minor]: Add async version of SQLChatMessageHistory Jun 5, 2024
@eyurtsev eyurtsev changed the title community[minor]: Add async version of SQLChatMessageHistory community[minor]: Add native async support to SQLChatMessageHistory Jun 5, 2024
@eyurtsev eyurtsev enabled auto-merge (squash) June 5, 2024 15:06
@eyurtsev eyurtsev removed the 🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature label Jun 5, 2024
@eyurtsev eyurtsev merged commit 8250c17 into langchain-ai:master Jun 5, 2024
42 checks passed
eyurtsev added a commit that referenced this pull request Jun 7, 2024
Hello @eyurtsev

- package: langchain-comminity
- **Description**: Add SQL implementation for docstore. A new
implementation, in line with my other PR ([async
PGVector](langchain-ai/langchain-postgres#32),
[SQLChatMessageMemory](#22065))
- Twitter handler: pprados

---------

Signed-off-by: ChengZi <[email protected]>
Co-authored-by: Bagatur <[email protected]>
Co-authored-by: Piotr Mardziel <[email protected]>
Co-authored-by: ChengZi <[email protected]>
Co-authored-by: Eugene Yurtsev <[email protected]>
@pprados pprados deleted the pprados/fix_sql_chat_history branch June 18, 2024 06:35
hinthornw pushed a commit that referenced this pull request Jun 20, 2024
…22065)

# package community: Fix SQLChatMessageHistory

## Description
Here is a rewrite of `SQLChatMessageHistory` to properly implement the
asynchronous approach. The code circumvents [issue
22021](#22021) by
accepting a synchronous call to `def add_messages()` in an asynchronous
scenario. This bypasses the bug.

For the same reasons as in [PR
22](langchain-ai/langchain-postgres#32) of
`langchain-postgres`, we use a lazy strategy for table creation. Indeed,
the promise of the constructor cannot be fulfilled without this. It is
not possible to invoke a synchronous call in a constructor. We
compensate for this by waiting for the next asynchronous method call to
create the table.

The goal of the `PostgresChatMessageHistory` class (in
`langchain-postgres`) is, among other things, to be able to recycle
database connections. The implementation of the class is problematic, as
we have demonstrated in [issue
22021](#22021).

Our new implementation of `SQLChatMessageHistory` achieves this by using
a singleton of type (`Async`)`Engine` for the database connection. The
connection pool is managed by this singleton, and the code is then
reentrant.

We also accept the type `str` (optionally complemented by `async_mode`.
I know you don't like this much, but it's the only way to allow an
asynchronous connection string).

In order to unify the different classes handling database connections,
we have renamed `connection_string` to `connection`, and `Session` to
`session_maker`.

Now, a single transaction is used to add a list of messages. Thus, a
crash during this write operation will not leave the database in an
unstable state with a partially added message list. This makes the code
resilient.

We believe that the `PostgresChatMessageHistory` class is no longer
necessary and can be replaced by:
```
PostgresChatMessageHistory = SQLChatMessageHistory
```
This also fixes the bug.


## Issue
- [issue 22021](#22021)
  - Bug in _exit_history()
  - Bugs in PostgresChatMessageHistory and sync usage
  - Bugs in PostgresChatMessageHistory and async usage
- [issue
36](langchain-ai/langchain-postgres#36)
 ## Twitter handle:
pprados

## Tests
- libs/community/tests/unit_tests/chat_message_histories/test_sql.py
(add async test)

@baskaryan, @eyurtsev or @hwchase17 can you check this PR ?
And, I've been waiting a long time for validation from other PRs. Can
you take a look?
- [PR 32](langchain-ai/langchain-postgres#32)
- [PR 15575](#15575)
- [PR 13200](#13200)

---------

Co-authored-by: Eugene Yurtsev <[email protected]>
hinthornw pushed a commit that referenced this pull request Jun 20, 2024
Hello @eyurtsev

- package: langchain-comminity
- **Description**: Add SQL implementation for docstore. A new
implementation, in line with my other PR ([async
PGVector](langchain-ai/langchain-postgres#32),
[SQLChatMessageMemory](#22065))
- Twitter handler: pprados

---------

Signed-off-by: ChengZi <[email protected]>
Co-authored-by: Bagatur <[email protected]>
Co-authored-by: Piotr Mardziel <[email protected]>
Co-authored-by: ChengZi <[email protected]>
Co-authored-by: Eugene Yurtsev <[email protected]>
@alew3
Copy link

alew3 commented Jul 3, 2024

Can you add in the documentation readme how to use async connections? Even with the PR, I'm getting errors.

@pprados
Copy link
Contributor Author

pprados commented Jul 4, 2024

Use:

history_engine = create_async_engine(url="postgresql+psycopg://user:password@localhost:5432)

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    return SQLChatMessageHistory( 
        session_id=session_id,
        connection=history_engine,
        engine_args={"echo": False},
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm PR looks good. Use to confirm that a PR is ready for merging. 🔌: postgres Related to postgres integrations size:L This PR changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants