add: per request statement timeout using prefer header#4584
add: per request statement timeout using prefer header#4584taimoorzaeem wants to merge 1 commit intoPostgREST:mainfrom
Conversation
d074eb9 to
2c5589f
Compare
5f1d601 to
6963e9a
Compare
|
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. |
a82c07f to
0d6370e
Compare
src/PostgREST/Plan.hs
Outdated
| -- 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 |
There was a problem hiding this comment.
I'm confused by all of this logic, why do we need to parse a time unit?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
postgrest/src/PostgREST/Query/PreQuery.hs
Line 51 in 8f5fe3f
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@taimoorzaeem Hm, so we can't avoid this logic with the above snippet?
There was a problem hiding this comment.
Yes. If we try to avoid this logic using the above snippet, we would end up with maintaining more state (keep extra pre-computed values, even when they are never used) so I think we should avoid it.
There was a problem hiding this comment.
Sorry for late reply here.
If we try to avoid this logic using the above snippet, we would end up with maintaining more state (keep extra pre-computed values, even when they are never used) so I think we should avoid it.
IMO we should cache the pg transformed value.
- Having to repeat this transformation logic for each request at the Plan level would be inefficient.
- It's not much more memory considering we only take child roles of the connection role:
postgrest/src/PostgREST/Config/Database.hs
Line 145 in ffa3938
- Also later on we could avoid this caching if
Prefer: timeoutis not used with Config flag for enabling/disabling preferences #2987. - There is more risk for errors with this Haskell logic.. say if pg changes format of the statement_timeout, very unlikely but overall it feels safer to have the transformation at the db level.
0d6370e to
6481e8e
Compare
6481e8e to
a37d497
Compare
1998a61 to
cef3feb
Compare
cd53ca3 to
356cecf
Compare
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 <taimoorzaeem@gmail.com>
356cecf to
a1f19e7
Compare
| -- Cached statement timeout settings converted to number of seconds. They | ||
| -- are never applied, only used to check max allowed timeout for a role | ||
| -- when "Prefer: timeout=" header is used. | ||
| , configRoleTimeoutSettings :: RoleTimeoutSettings |
There was a problem hiding this comment.
IMO we should cache the pg transformed value
@steve-chavez How about an internal config to store the transformed values?
There was a problem hiding this comment.
Yes, this looks much better 👍
Adds a feature to set
statement_timeoutusingPrefer: timeoutheader. This also introduces aPGRST129error which is returned when the timeout preferred exceeds the per-role timeout, which prevents misuse of this feature.Closes #4381.