Skip to content

Conversation

@taimoorzaeem
Copy link
Collaborator

@taimoorzaeem taimoorzaeem commented Dec 29, 2025

Adds a feature to set statement_timeout using Prefer: timeout header. This also introduces a PGRST129 error which is returned when the timeout preferred exceeds the per-role timeout, which prevents misuse of this feature.

Closes #4381.

  • Implementation
  • Tests
  • Docs

@taimoorzaeem taimoorzaeem force-pushed the add/per-request-timeout branch from d074eb9 to 2c5589f Compare December 29, 2025 16:37
@taimoorzaeem taimoorzaeem marked this pull request as draft December 29, 2025 16:40
@taimoorzaeem taimoorzaeem force-pushed the add/per-request-timeout branch 3 times, most recently from 5f1d601 to 6963e9a Compare January 1, 2026 07:48
@taimoorzaeem taimoorzaeem changed the title [WIP] add: per request statement timeout using prefer header add: per request statement timeout using prefer header Jan 1, 2026
@taimoorzaeem taimoorzaeem marked this pull request as ready for review January 1, 2026 07:48
@steve-chavez
Copy link
Member

We should also fail in case a value exceeds the per role timeout. Otherwise it's abusable.

This failure should happen at the plan level, before hitting the db. I think it will need a new error code.

@taimoorzaeem taimoorzaeem marked this pull request as draft January 2, 2026 08:23
@taimoorzaeem taimoorzaeem force-pushed the add/per-request-timeout branch 5 times, most recently from a82c07f to 0d6370e Compare January 7, 2026 07:13
@taimoorzaeem taimoorzaeem marked this pull request as ready for review January 7, 2026 07:15
@taimoorzaeem taimoorzaeem added the enhancement a feature, ready for implementation label Jan 7, 2026
-- It is safe to use fromJust because the string being read is guaranteed
-- to be number after striping the unit.
stripUnitAndGetInt unit val = fromJust $ BS.stripSuffix unit val >>= readMaybe
rtValueToSeconds :: ByteString -> Int
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused by all of this logic, why do we need to parse a time unit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We should also fail in case a value exceeds the per role timeout. Otherwise it's abusable

I'm confused by all of this logic, why do we need to parse a time unit?

That's because the statement_timeout value of the role could be like 1min or 100ms depending upon the role. So, we need to throw an error depending on whether the timeout exceeds role setting or not and for that, we must parse the value, I think.

Copy link
Member

Choose a reason for hiding this comment

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

Can we do the conversion in postgres to avoid the parsing? For example with:

select extract(epoch from current_setting('statement_timeout', false)::interval)::int;

That should give you the number of seconds regardless of the input format.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's great.

However, if we do this conversion at the time of querying the role settings, that would change the original role settings, which we explicitly add to pre-query (BTW, I'm not sure why we do this, wouldn't postgres already know the settings?) here:

roleSettingsSql = setConfigWithDynamicName <$> HM.toList (fromMaybe mempty $ HM.lookup authRole configRoleSettings)

So, we would then have to keep the two sets of role settings, one with the conversion applied on and the original ones without the conversion.

Copy link
Member

Choose a reason for hiding this comment

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

we explicitly add to pre-query (BTW, I'm not sure why we do this, wouldn't postgres already know the settings?)

The settings set via ALTER ROLE ... only apply when logging in with that role. PostgreSQL does not apply them when doing a SET ROLE. That means, these role-specific settings are only set when we do it manually.

Copy link
Member

@steve-chavez steve-chavez Jan 18, 2026

Choose a reason for hiding this comment

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

@taimoorzaeem Hm, so we can't avoid this logic with the above snippet?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. If we try to avoid this logic using the above snippet, we would end with maintaining more state (keep extra pre-computed values, even when they are never used) so I think we should avoid it.

@taimoorzaeem taimoorzaeem marked this pull request as draft January 12, 2026 07:27
@taimoorzaeem taimoorzaeem force-pushed the add/per-request-timeout branch from 0d6370e to 6481e8e Compare January 13, 2026 05:40
@taimoorzaeem taimoorzaeem marked this pull request as ready for review January 13, 2026 05:41
@taimoorzaeem taimoorzaeem force-pushed the add/per-request-timeout branch from 6481e8e to a37d497 Compare January 15, 2026 14:56
Adds a feature to set `statement_timeout` using `Prefer: timeout`
header. This also introduces a `PGRST129` error which is returned
when the timeout preferred exceeds the per-role timeout, which
prevents misuse of this feature.

Signed-off-by: Taimoor Zaeem <[email protected]>
@taimoorzaeem taimoorzaeem force-pushed the add/per-request-timeout branch from a37d497 to 1998a61 Compare January 18, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement a feature, ready for implementation

Development

Successfully merging this pull request may close these issues.

Per-request timeout

3 participants