Commit Graph
4606 Commits
Author SHA1 Message Date
renovate[bot]andWolfgang Walther 3ca876da62 chore(deps): update actions/checkout action to v6.0.3 2026-06-04 09:09:49 +00:00
Laurence IslaandSteve Chavez 416a15480f fix: request failures when work_mem is set on a role 2026-06-03 13:45:34 -05:00
Wolfgang Walther a149405d11 ci: remove deprecation warning
app-id was replaced with client-id
2026-06-03 10:09:38 +02:00
netandWolfgang Walther 3d596e2dbc fix: don't mention retrying in the database connection error message
The PGRST000 database connection error message was "Database connection
error. Retrying the connection.", but reconnection attempts are already
logged separately by the reconnection observation, and on fatal errors
(e.g. authentication failure) PostgREST does not retry at all. Drop the
"Retrying the connection." part, leaving "Database connection error.".
2026-06-03 08:04:40 +00:00
Pedro Gil MoraandWolfgang Walther fae58174fa docs: Add efcore-postgrest library to client-side libraries 2026-06-02 08:19:45 +00:00
Wolfgang Walther 840d3f99ed ci(ci): avoid running build jobs twice on pushes to main
It's enough to run the build jobs in the release pipeline, no need to
run them on the push event as well.
2026-06-02 10:08:16 +02:00
Wolfgang Walther 871aa058f8 ci(release): only update docker description from devel release
This condition was accidentally removed when merging 4 release jobs into
2.
2026-06-02 10:07:37 +02:00
Wolfgang Walther 8552c66c1e ci: Use FreeBSD VM instead of cirrus 2026-06-02 07:36:59 +00:00
netandWolfgang Walther 097a1de67d chore: sort config dump alphabetically
The config dump in Config.hs listed db-config, db-pre-config and the
db-pool-* settings out of alphabetical order, while the rest of the dump
was sorted. Now the whole dump is consistently alphabetical and update
the expected IO test configs to match.
2026-06-02 07:32:11 +00:00
Wolfgang Walther ed4b68c364 test(spec): remove obsolete extra search path from postgis tests
This was brought over in the last commit, because the postgis was
re-using the same config as another test. Now it has a separate config,
so we can reduce it a bit.
2026-06-02 06:49:15 +00:00
Wolfgang Walther 268ab00ed9 test(spec): inline config into test suite
Previously, information about each test-suite was repeated in 3 separate
places:
- as a label and as implicit knowledge in the test-suite itself,
- as a comment in Main.hs, and
- as a configuration in SpecHelper.hs.

With this change, there will be a single source of truth in the test
suite itself. This will allow a single test-suite to easily test
multiple different configurations.
2026-06-02 06:49:15 +00:00
Wolfgang Walther 7803960cd1 test(spec): fix test labels 2026-06-02 06:49:15 +00:00
Wolfgang Walther 0e46474cb2 test(spec): fix typo in comment 2026-06-02 06:49:15 +00:00
Wolfgang Walther 7c806a2bf9 test(spec): move two tests with basic config into list
Everything that uses withApp is in that list.
2026-06-02 06:49:15 +00:00
Wolfgang Walther c2d32be3c5 test(spec): remove obsolete ANALYZE calls
These are now part of the with- helpers.
2026-06-02 06:49:15 +00:00
Michał KłeczekandTaimoor Zaeem 13c0e7061e refactor: simplify control flow in App.postgrest
Currently, authentication and response execution each unwrap ExceptT with separate runExceptT calls, which split the main request flow across nested pattern matching and Either handling. Control flow is complex and difficult to understand.

The goal of this change is to make request execution as sequential
monadic code with clear error handling.

To implement that, request handling is now run in ExceptT over WriterT (Last ByteString) IO monad stack. Auth role is written after authentication succeeds and further returned along the response. Thanks to it response observation generation is centralized at the end of request handling.

It was necessary to abstract monad stack in getAuthResult, lookupJwtCache, postgrestResponse, and withTiming to enable introduction of WriterT.
2026-06-02 11:28:19 +05:00
Wolfgang Walther 1d6e0bd35f nix(loadtest): report percentage change
This reports the percentage change between the current head branch and
the main branch, which is exactly the number we'll want to make our
decisions on "success or fail" on.

CI failures will initially be reported for regressions of 5% or more on
an individual number.
2026-06-01 20:49:35 +00:00
Wolfgang Walther ff92846e64 nix(loadtest): report multiple percentiles at once
We can look at the data over time and see which percentile works best
for our purpose.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 640039a180 nix(loadtest): move errors into mixed
Because we separate loadtest results per URL now, we can move the error
tests into the regular mixed bag of loadtests - we will be able to tell
from the misspelled URLs when we hit a regression in that area.

We should be able to do similar things for JWT tests, but we'll need
more infrastructure here.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 59dffc258a nix(loadtest): report latency instead of rate
We previously used "rate", i.e. number of requests per second, as the
primary metric to judge loadtest results. However, this has always been
varying from run to run quite a bit, especially in CI where other jobs
possibly run on the same VM host.

The run-to-run variance has massively increased after splitting the
results up per request. Example run in CI with rate on the PR
introducing this change (on which we would expect no change at all):

| rate [1/s]                         |   main |   head |    Δ |
|:-----------------------------------|-------:|-------:|-----:|
| /                                  |    9.4 |    9.5 |   1% |
| /actors                            |  870.4 | 1023.0 |  18% |
| /actors?actor=eq.1                 |  188.5 |  198.6 |   5% |
| /actors?actor=eq.1&columns=name    |  197.3 |  167.1 | -15% |
| /actors?select=*,roles(*,films(*)) |  153.9 |  144.9 |  -6% |
| /films?columns=id,title            |  157.9 |  182.6 |  16% |
| /films?columns=id,title,year,...   |   87.0 |   87.1 |   0% |
| /roles                             |  204.5 |  267.3 |  31% |
| /rpc/call_me                       |  231.3 |  208.8 | -10% |
| /rpc/call_me?name=John             |  212.2 |  201.7 |  -5% |

From the data we can easily tell that the very reason that rate as a
paramter has only worked, so far, because the data was *heavily*
dominated by the requests on the root endpoint for OpenAPI. The longer
duration makes the request much less vulnerable for concurrent activity.
For all other requests its essentially not possible to judge the effect
of a PR this way.

One way to counter this would be to massively increase the time the
loadtest runs. More samples will result in a smoother average. However,
that's not practical for usability of CI. In the original PR #1812 I
already evaluated using the *minimum latency* as the most reliable
criteriumi, but this has never really caught on. The theory behind this
is: The variation in timings between requests is happening because of
concurrent activity, priority chosen by the scheduler, availability of
resources and such - all factors *outside* our control, and *irrelevant*
to the Haskell code we're writing.

Using the minimum latency is an estimation of how fast the code can run
*in the best case*. This might not be a number relevant for production,
but it's much more directly related to the code we write.

Here's to show how variation becomes *much* smaller with minimum latency
as the parameter:

| min latency [μs]                   |     main |   head |    Δ |
|:-----------------------------------|---------:|-------:|-----:|
| /                                  |   1275.3 | 1263.6 |  -1% |
| /actors                            |     10.0 |    9.9 |  -1% |
| /actors?actor=eq.1                 |     50.7 |   48.3 |  -5% |
| /actors?actor=eq.1&columns=name    |     54.1 |   54.0 |   0% |
| /actors?select=*,roles(*,films(*)) |     63.2 |   61.9 |  -2% |
| /films?columns=id,title            |     51.1 |   50.7 |  -1% |
| /films?columns=id,title,year,...   |    121.9 |  121.8 |   0% |
| /roles                             |     42.9 |   42.6 |  -1% |
| /rpc/call_me                       |     45.6 |   45.4 |   0% |
| /rpc/call_me?name=John             |     44.4 |   44.2 |   0% |

Since we're separating results per request now, we can only sensibly
focus on *one* parameter - otherwise this would get really clunky
UI-wise. Especially for automated CI failures, minimum latency is the
logical choice.

This commit starts using minimum latency, i.e. P0, but any percentile
should be an improvement over the status quo. A later commit will change
to a different P-value.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 8a9f98371e nix(loadtest): group results by status, method and URL
Different requests hit different code paths and perform very
differently. By looking at each request type separately, we should be
able to get a much better idea of what kind of change in performance
we're looking at and where the root cause might be.

It will hopefully also allow us to migrate some of the other test-cases
into the main loadtest.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 5cdf2e0569 nix(loadtest): remove noise from report
Ultimately, we only look at the `rate` column, so we can just as well
remove all other columns.

This makes the next step, when we split results by request type, much
less noisy.
2026-06-01 20:49:35 +00:00
Taimoor ZaeemandSteve Chavez 669fc9ede8 docs: restructure PostGIS page
Restructure PostGIS page with order:

- `Accept: application/geo+json` request example
- Generated column example
- String representation example

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-01 12:59:15 -05:00
Michał KłeczekandSteve Chavez 0df56f9ea8 refactor: assemble main transaction session in MainTx
This change makes the API surface between MainTx and App smaller.

Currently, App reconstructs a database transaction by unpacking the isolation
level, transaction mode, DbHandler, and transaction runner returned by MainTx.
That exposes MainTx internals at the call site even though MainTx already owns
query setup, execution, decoding, and rollback behavior.

The goal is to keep transaction assembly in MainTx while App remains responsible
for pool execution, database error mapping, and response orchestration. DbTx now
carries the assembled SQL session, and App passes that session directly to the
connection pool.
2026-05-31 15:52:56 -05:00
Michał KłeczekandSteve Chavez 56ad5a9324 refactor: get rid of dbQueryTimings from SchemaCache
Schema cache query timings are only needed immediately after a schema-cache reload to emit SchemaCacheQueriedObs. Storing them inside SchemaCache makes the cache carry transient observability data that is not part of the cached schema state and is never used by request handling.

This change makes querySchemaCache to return query timings in a tuple in parallel to SchemaCache and removes dbQueryTimings field.
2026-05-31 14:20:35 -05:00
Taimoor ZaeemandSteve Chavez 9162cea7ba test(io): remove unused config variables from config test
Config variables are tested already via reading the config files in
the `configs/` directory.

If more are to be tested, it should be done via adding a file in
`configs/` and compare it with its associated file in `configs/expected/`.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-30 09:51:26 -05:00
Taimoor ZaeemandSteve Chavez e1d547623e nix(docs): print message to console on script runs
It's not immediately visible that these scripts are run when
doing `postgrest-docs-check`.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-27 15:23:59 -05:00
Michał KłeczekandSteve Chavez 998d232ac0 docs: PGRST107 error should map to 406 not to 415 2026-05-27 14:37:23 -05:00
Michał KłeczekandWolfgang Walther 1a6ba2072c refactor: Simplify App.initServerSocket
This change gets rid of unnecessary explicit bindRandomPortTCP in initServerSocket. Returned port value was ignored in removed code anyway as assigned port retrieval from an open socket is handled elsewhere.
2026-05-24 23:56:05 +02:00
renovate[bot]andWolfgang Walther ae00c04faf chore(deps): update docker/login-action action to v4.2.0 2026-05-22 20:54:17 +00:00
renovate[bot]andWolfgang Walther e0e14a1fe4 chore(deps): update docker/setup-buildx-action action to v4.1.0 2026-05-22 20:52:03 +00:00
Taimoor ZaeemandSteve Chavez 901624a891 chore: add changelog entry for v14.12
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-21 10:26:17 -05:00
Michał KłeczekandSteve Chavez 913fe001e5 refactor(remove): schema cache load delay config
Remove internal schema cache load and relationship load sleep settings plus
the delay wrappers they enabled. Drop IO tests that depended on the removed
settings.
2026-05-19 10:59:27 -05:00
Michał KłeczekandSteve Chavez 86d6ed10bb test: cover stale schema cache database error
Add an IO test that drops a table while schema cache reload is delayed. It verifies the stale cache path returns PostgreSQL 42P01 and the refreshed cache returns PGRST205.
2026-05-19 09:11:04 -05:00
renovate[bot]andWolfgang Walther 55f9c45899 chore(deps): update codecov/codecov-action action to v6.0.1 2026-05-19 07:04:42 +00:00
Michał KłeczekandTaimoor Zaeem 07938aaab2 amend: Move #4622 to proper Changelog section 2026-05-19 10:55:53 +05:00
Wolfgang Walther 61da5dd88b nix(loadtest): prevent timing errors for worst-case JWT test
Instead of taking wild guesses at the runtime of the target generation
itself, we're just making sure to reset the system time to a fixed value
when we ultimately start PostgREST. This allows us to create the right
JWT expiry values ahead of time.
2026-05-18 16:23:37 +00:00
Wolfgang Walther d9f73ac71b nix(loadtest): remove duplicate line 2026-05-18 16:23:37 +00:00
Taimoor ZaeemandWolfgang Walther e6d8d95c0a chore: remove unplanned TODO in Logger.hs
We decided against doing this in #4913, therefore removing it. With that,
also mentioning that control flow never reaches there to avoid confusion.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-18 16:23:08 +00:00
Wolfgang Walther 9d67febb93 ci(release): merge 4 jobs into 2
No need to do this in as many jobs. Splitting all the github stuff from
docker stuff into two jobs is enough. This still allows to conditionally
enable docker jobs in contributors repos, depending on whether the
relevant docker credentials are provided - but avoids using too many
concurrent runners.
2026-05-18 16:22:49 +00:00
steve-chavez 6220ab3f31 test: adjust test_positive_pool_metric
Adjusted so it waits for liveness instead of requiring sleeping
2026-05-18 10:46:02 -05:00
steve-chavez 1eba9855c1 test: change wait_for_readiness to an enum
This so we can wait for both readiness and liveness
2026-05-18 10:45:36 -05:00
Michał KłeczekandSteve Chavez a297391071 fix: implement connection tracking in metrics
Right now metrics observation handler does not track database connections but updates a single Gauge based on HasqlPoolObs events. This is problematic because Hasql pool reports various connection events in multiple phases. The connection state machine is not simple and to precisely report the number of connections in various states, it is necessary to track their lifecycles.

This change adds a ConnTrack data structure and logic to track database connections lifecycles. At the moment it supports "connected" and "inUse" connection counts precisely. The "pgrst_db_pool_available" metric is implemented on top of ConnTrack instead of a simple Gauge.
2026-05-18 10:09:00 -05:00
Wolfgang Walther 4f9bc89ab2 nix(loadtest): remove outdated PGRST_DB_URI default
This was required for v9 and earlier, but these don't build with the
current nix invocation anymore anyway. Even loadtesting against v10 does
not work, because `--version` is used in one of the wait scripts and
this was only added in v11.2.

So no need to pretend we'd support comparing against older versions.
2026-05-18 15:18:05 +02:00
Taimoor ZaeemandWolfgang Walther 084a8eca55 test(io): move utility functions to util.py
The functions `drain_stdout` and `match_log` should be in `util.py`
so they can be reused in other modules.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-18 12:54:08 +00:00
Wolfgang Walther ed344c795a ci(release): run docker job on regular VM runner
Tried to run it on a -slim runner in fb24b6b3, but the result is that no
docker socket is available. This jobs needs one of the big runners.
2026-05-18 14:46:21 +02:00
Wolfgang Walther c335da9334 ci: avoid running pg18 tests twice
We already test PG18, the default, with the coverage job, so why run it
twice?
2026-05-18 14:06:16 +02:00
Wolfgang Walther fb24b6b37f ci: use -slim runner for small jobs
No need to spin up full VM runners for small automation tasks, when we
can use single-CPU runners in containers instead.

https://docs.github.com/en/actions/reference/runners/github-hosted-runners#single-cpu-runners

(some of this will potentially not work, because dependencies in the
slim image might not be available - however, it makes no sense to create
this as a PR, because all jobs touched here run on branches only. Thus
pushing directly to main)
2026-05-18 14:05:41 +02:00
steve-chavez 8868d13214 test: adjust sleep in test_positive_pool_metric
Otherwise it's not enough time for the pool metric to
reach a negative value.
2026-05-17 16:39:11 -05:00
Wolfgang Walther c7260bddab test: consistently analyze tables exactly once
Disabling the autovacuum daemon should also help reproducibility in
theory, although I don't know of any cases where we hit a problem with
that.

VACUUM changes the order of rows that PostgreSQL returns for some table
without explicit ordering, thus doing the latter to make it consistently
reproducible.

After ANALYZE estimates are 100% exact for the moment, so some requests
which returned 206 Partial Response now return 200 instead. The fact
that PostgREST returns 206 on an unfiltered endpoint can probably be
considered a bug.
2026-05-17 20:03:15 +00:00