8000 Driver tests for full `lib/pq` connection + necessary fixes by brandur · Pull Request #883 · riverqueue/river · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Driver tests for full lib/pq connection + necessary fixes #883

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 1 commit into from
May 8, 2025

Conversation

brandur
Copy link
Contributor
@brandur brandur commented May 6, 2025

So it turns out that while bearing some relation to lib/pq through
various pieces that sqlc pulls in, the riverdatabasesql driver didn't
actually work when used with lib/pq. When testing it, we'd open a
sql.DB pool via Pgx, so Pgx was doing all the heavy lifting.

Here, add an alternate driver test strategy to test riverdatabasesql
with a lib/pq pool, thereby ensuring that the full range of operations
works even with no Pgx in the mix at all.

Things were broken, so we get those fixed up. There we two main
problems:

  • As described in Elector interval field value out of range #545, lib/pq doesn't handle intervals correctly, and
    reads them in as ints, which is a big problem because they're in
    nanoseconds. We work around this by injecting intervals (like leader
    TTLs) an second floats instead, which really doesn't feel that much
    worse.

  • The custom bits class for unique_states didn't work. To fix this I
    move to an alternate strategy of inserts unique_states as an
    integer, a technique that I've been using in SQLite because there's no
    bits type. I could make a strong argument that the use of an integer
    over bits would've been a better design from the get go anyway,
    because it makes all the bit-wise arithmetic much simpler as you use
    C-style conventions like states & (1 << 3) that are very widespread
    and well understood. Either way though, things work reasonably well if
    we insert as an integer, then transition to storage in bits.

Fixes #545 and #566. Supersedes #882.

@brandur brandur force-pushed the brandur-lib-pq-full-testing branch 3 times, most recently from bc7a0a2 to 33a2de3 Compare May 6, 2025 03:38
@brandur brandur requested a review from bgentry May 6, 2025 03:42
@brandur
Copy link
Contributor Author
brandur commented May 6, 2025

@bgentry Mind taking a look at this one?

Copy link
Contributor
@bgentry bgentry left a comment
8000

Choose a reason for hiding this comment

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

It's always a bit unfortunate to have to move more in the direction of the lowest common denominator between drivers, but it's tolerable here. In the event we ever need to add another job state it might we'll need more than 8 bits and will need to adjust the approach.

@@ -9,16 +9,17 @@ CREATE UNLOGGED TABLE river_leader(

-- name: LeaderAttemptElect :execrows
INSERT INTO /* TEMPLATE: schema */river_leader (leader_id, elected_at, expires_at)
VALUES (@leader_id, coalesce(sqlc.narg('now')::timestamptz, now()), coalesce(sqlc.narg('now')::timestamptz, now()) + @ttl::interval)
-- @ttl is inserted as
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure what this comment is meant to convey

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah doh, I started a comment, but didn't finish it. I just put this more expounded version in instead:

-- @ttl is inserted as as seconds rather than a duration because `lib/pq` doesn't support the latter

Comment on lines +997 to +999
// lib/pq reads in `bits` (like `bits(8)`) as a bit string that's a normal
// decimal integer like 1111_1111 (_not_ 0b1111_1111). This function converts it
// back to binary representation. See the test suite for examples.
Copy link
Contributor

Choose a reason for hiding this comment

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

pq 🤦‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah haha. There might be some other way around this, but at least this isn't that bad.

@philippgille
Copy link

Does this also fix #566?

@bgentry
Copy link
Contributor
bgentry commented May 7, 2025

@philippgille it should fix it! 🤞

So it turns out that while bearing some relation to `lib/pq` through
various pieces that sqlc pulls in, the `riverdatabasesql` driver didn't
actually work when used with `lib/pq`. When testing it, we'd open a
`sql.DB` pool _via_ Pgx, so Pgx was doing all the heavy lifting.

Here, add an alternate driver test strategy to test `riverdatabasesql`
with a `lib/pq` pool, thereby ensuring that the full range of operations
works even with no Pgx in the mix at all.

Things were broken, so we get those fixed up. There we two main
problems:

* As described in #545, `lib/pq` doesn't handle intervals correctly, and
  reads them in as ints, which is a big problem because they're in
  nanoseconds. We work around this by injecting intervals (like leader
  TTLs) an second floats instead, which really doesn't feel that much
  worse.

* The custom bits class for `unique_states` didn't work. To fix this I
  move to an alternate strategy of inserts `unique_states` as an
  integer, a technique that I've been using in SQLite because there's no
  `bits` type. I could make a strong argument that the use of an integer
  over `bits` would've been a better design from the get go anyway,
  because it makes all the bit-wise arithmetic much simpler as you use
  C-style conventions like `states & (1 << 3)` that are very widespread
  and well understood. Either way though, things work reasonably well if
  we insert as an integer, then transition to storage in bits.

Fixes #545 and #566. Supersedes #882.
@brandur brandur force-pushed the brandur-lib-pq-full-testing branch from be8d1eb to bff8718 Compare May 8, 2025 00:16
@brandur
Copy link
Contributor Author
brandur commented May 8, 2025

It's always a bit unfortunate to have to move more in the direction of the lowest common denominator between drivers, but it's tolerable here.

Yeah for sure. I was reasonably happy that that none of the hacks to get this working were that gross. Code's different, but not obvious that much worse.

In the event we ever need to add another job state it might we'll need more than 8 bits and will need to adjust the approach.

Yeah, although most of the integers we're working with are at least four bytes, so they should still mostly work in case we need more than those 8 bits.

@brandur
Copy link
Contributor Author
brandur commented May 8, 2025

Thanks!

@brandur brandur merged commit b17ec85 into master May 8, 2025
10 checks passed
@brandur brandur deleted the brandur-lib-pq-full-testing branch May 8, 2025 00:19
brandur added a commit that referenced this pull request May 8, 2025
This is just a dumb one where I was addressing code review feedback from
the `lib/pq` change #883, specifically a half finished comment on
`@ttl`, then forgot to push the change up to my branch before merging
it. Here, address the problem by finishing the comment.
brandur added a commit that referenced this pull request May 8, 2025
This is just a dumb one where I was addressing code review feedback from
the `lib/pq` change #883, specifically a half finished comment on
`@ttl`, then forgot to push the change up to my branch before merging
it. Here, address the problem by finishing the comment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Elector interval field value out of range
3 participants
0