Skip to content

Add Postgres database#863

Open
benthecarman wants to merge 1 commit intolightningdevkit:mainfrom
benthecarman:postgres
Open

Add Postgres database#863
benthecarman wants to merge 1 commit intolightningdevkit:mainfrom
benthecarman:postgres

Conversation

@benthecarman
Copy link
Copy Markdown
Contributor

Add a PostgresStore implementation behind the postgres feature flag, mirroring the existing SqliteStore. Uses tokio-postgres (async-native) with an internal tokio runtime for the sync KVStoreSync trait, following the VssStore pattern.

Also gates sqlite behind a feature flag, since most tests relied on this, we ended up needing to gate a lot of them behind the flag. Curious on thoughts on how to handle this best

@benthecarman benthecarman requested a review from tnull April 1, 2026 19:55
@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented Apr 1, 2026

👋 Thanks for assigning @Camillarhi as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Copy link
Copy Markdown
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

Took a first high-level look.

Also gates sqlite behind a feature flag, since most tests relied on this, we ended up needing to gate a lot of them behind the flag. Curious on thoughts on how to handle this best

Not sure I'm following? Why do we want to feature-gate tests based on SQLite?

Also tagging @tankyleo as a secondary reviewer here as he has a lot of recent experience with Postgres on VSS Server.

Comment thread .github/workflows/postgres-integration.yml Outdated
Comment thread src/io/postgres_store/mod.rs Outdated

// An internal runtime we use to avoid any deadlocks we could hit when waiting on async
// operations to finish from a sync context.
internal_runtime: Option<tokio::runtime::Runtime>,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we could avoid using an internal runtime for this and rather just reuse crate::runtime::Runtime, if we wanted. Though, when upstreaming to LDK we'll need to rethink all of this anyways (cf. VssStore upstreaming PR).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah I just copied VSS to be safe.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, let's drop the extra runtime then.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems to be unaddressed? (cc @benthecarman). Or I guess you interpreted 'then' as 'when we upstream'? IMO it's likely unnecessary in this case, so might as well do it now, but let me know if you'd rather keep it for now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ohh missed your other comment, fixed

Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs Outdated

/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
/// previously configured.
#[cfg(feature = "sqlite")]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we suddenly introduce features? We so far held off and meant to do that in a dedicated PR at some point for this or next release. Is it necessary to make Postgres work?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

okay removed for now

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Seems the postgres feature is still present in the current version?

@tnull tnull requested a review from tankyleo April 2, 2026 11:10
@benthecarman benthecarman self-assigned this Apr 2, 2026
@benthecarman benthecarman force-pushed the postgres branch 2 times, most recently from b5d297e to e8f478b Compare April 3, 2026 19:57
@benthecarman
Copy link
Copy Markdown
Contributor Author

Did fixes in follow up commits for ease of review.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 2nd Reminder

Hey @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Copy Markdown
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

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

Verbose review, please dismiss aggressively :)

Comment thread src/builder.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs Outdated
Comment thread src/builder.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs Outdated
@benthecarman
Copy link
Copy Markdown
Contributor Author

@tankyleo addressed most of your comments. Lots of docs improvements. Better handling around the db name and creating the db. And did the code clean ups + test improvements you suggested.

@benthecarman benthecarman force-pushed the postgres branch 4 times, most recently from a8589ea to a43b13b Compare April 8, 2026 01:08
@tankyleo tankyleo self-requested a review April 9, 2026 15:52
@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 2nd Reminder

Hey @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs Outdated
@benthecarman benthecarman force-pushed the postgres branch 2 times, most recently from 3bb9810 to 437f11f Compare April 14, 2026 21:03
@tankyleo tankyleo self-requested a review April 14, 2026 21:42
Copy link
Copy Markdown
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

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

two small nits thank you

Comment thread src/builder.rs Outdated
Comment thread src/builder.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
@benthecarman
Copy link
Copy Markdown
Contributor Author

benthecarman commented Apr 14, 2026

two small nits thank you

fixed

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @tnull! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 2nd Reminder

Hey @tnull! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/builder.rs Outdated
Comment thread src/io/postgres_store/mod.rs Outdated
@tnull
Copy link
Copy Markdown
Collaborator

tnull commented Apr 28, 2026

@benthecarman Any update here?

@benthecarman benthecarman force-pushed the postgres branch 3 times, most recently from 85652a1 to f81b8a0 Compare May 3, 2026 19:33
@benthecarman benthecarman requested review from Camillarhi and tnull May 4, 2026 01:16
@benthecarman
Copy link
Copy Markdown
Contributor Author

Responded to review

Comment thread src/io/postgres_store/mod.rs Outdated
Comment on lines +392 to +394
/// Round-robin (rather than `tokio::select!` over all slot locks) is preferred so [`POOL_SIZE`]
/// can be `cfg`-conditional without rewriting select arms. The trade-off: under contention the
/// fallback `lock().await` may park on a busy slot while another frees up a moment later.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm not sure it's worth dropping the tokio::select to help the tests ? You probably saw this I pass --test-threads 1 over at VSS when running tests to avoid flooding connections like you mention above. But perhaps there's a better path that doesn't require passing this flag (including maybe sticking to what you have here your call).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Switched to be a select, just have a smaller one for tests

Comment thread src/builder.rs Outdated
kv_table_name,
tls_config,
)
.map_err(|_| BuildError::KVStoreSetupFailed)?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we log the error returned here, like what I do in #893 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

that needs build_with_store_and_logger. Maybe just need to have one of these depend on the other

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Landed #893, please rebase to use build_with_store_and_logger.

Comment thread src/io/postgres_store/mod.rs Outdated

// An internal runtime we use to avoid any deadlocks we could hit when waiting on async
// operations to finish from a sync context.
internal_runtime: Option<tokio::runtime::Runtime>,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems to be unaddressed? (cc @benthecarman). Or I guess you interpreted 'then' as 'when we upstream'? IMO it's likely unnecessary in this case, so might as well do it now, but let me know if you'd rather keep it for now.

/// `"postgres://user:password@localhost/ldk_db"`.
///
/// The given `db_name` will be used or default to [`DEFAULT_DB_NAME`]. The
/// `connection_string` must not include a `dbname` when `db_name` is set, providing both
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe in VSS Server we discovered that different providers have different names for default databases, and we'll need to connect to the default database to be able to initialize the configured database if it's not pre-existing. It seems we might need to add the same config option for 'default db' here, too, which will only be used for the initial connection? Or do we see a better option (given this is a quite ugly/confusing API)?

Copy link
Copy Markdown
Contributor Author

@benthecarman benthecarman May 5, 2026

Choose a reason for hiding this comment

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

@tankyleo discussed this and thought it might be better to punt on it for now. You can always just use whatever bespoke default db they use as your db instead of the DEFAULT_DB_NAME in your connection string. But yeah can add if you think it'll cause issues

Comment thread src/io/postgres_store/mod.rs Outdated
Comment thread src/io/mod.rs Outdated
/// TLS configuration for PostgreSQL connections.
#[cfg(any(feature = "postgres", feature = "uniffi"))]
#[derive(Debug, Clone)]
pub struct PostgresTlsConfig {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't belong into this file but should be part of the postgres_store sub-module or if we deem it part of the user-facing builder API, it should be in builder.rs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Put it here so the bindings had access to it. Was unsure if we wanted to have the bindings require postgres enabled or not. Currently its behind the feature flag but we still need the type exposed

Copy link
Copy Markdown
Collaborator

@tnull tnull May 6, 2026

Choose a reason for hiding this comment

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

We usually have the pattern of exposing any types required by the bindigns by re-exporting at crate level via the use statements in ffi/types.rs. That should work here, too? I.e., have the type live in the sub-module, and just expose it via that at crate level under uniffi?

We def. want to expose it also under bindings. While probably not super interesting for Swift/Kotlin mobile users, we also have some Go bindings users for which postgres could be interesting at some point, potentially.

Comment thread src/builder.rs Outdated
///
/// If `tls_config` is `Some`, TLS will be used for database connections. A custom CA
/// certificate can be provided via
/// [`PostgresTlsConfig::certificate_pem`](io::postgres_store::PostgresTlsConfig::certificate_pem),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Given the PostgresTlsConfig currently only holds one field, should certificate_pem just be an optional field directly on build_with_postgres_store? And then we could use PostgresTlsConfig internally only for now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah this solves the bindings issue above too

Add a PostgresStore implementation behind the "postgres" feature
flag, mirroring the existing SqliteStore. Uses tokio-postgres
(async-native) with an internal tokio runtime for the sync
KVStoreSync trait, following the VssStore pattern.

Includes unit tests, integration tests (channel full cycle and
node restart), and a CI workflow that runs both against a
PostgreSQL service container.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @Camillarhi! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment thread Cargo.toml

[features]
default = []
postgres = ["dep:tokio-postgres", "dep:native-tls", "dep:postgres-native-tls"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hmm, we probably want to introduce features even before the next release, but still not a fan of just adding a one-off feature for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants