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
0d6370e to
6481e8e
Compare
6481e8e to
a37d497
Compare
1998a61 to
cef3feb
Compare
cd53ca3 to
356cecf
Compare
356cecf to
a1f19e7
Compare
001ee79 to
e77acb3
Compare
e52e45f to
77602ac
Compare
4a92e87 to
c8f4f27
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 or global timeout. Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
c8f4f27 to
7c49b66
Compare
| failPreferTimeout Preferences{preferTimeout=(Just (PreferTimeout t)), preferHandling=Just Strict} AppConfig{..} AuthResult{..} = | ||
| case roleTimeout of | ||
| Nothing -> Right () | ||
| Just rt -> when (t > rt) $ Left $ ApiRequestError $ TimeoutConstraintError rt |
There was a problem hiding this comment.
This check is problematic because it undermines the whole idea of this header.
Who would want to set the timeout header to a value less than the role setting? What for?
The only realistic use case is that a client might want to increase statement_timeout for a particular query.
So sensible limit is greater than the role setting. Don't know: maybe 2x role setting should be the limit? But then - why not simply set the role setting to a greater value?
Thinking about it: it looks like having any limit is contradictory to the idea of this header. OTOH not having a limit is a security vulnerability. No good choice here, I'm afraid.
@taimoorzaeem @steve-chavez WDYT?
There was a problem hiding this comment.
This check is problematic because it undermines the whole idea of this header.
Thinking about it: it looks like having any limit is contradictory to the idea of this header. OTOH not having a limit is a security vulnerability. No good choice here, I'm afraid.
I think you're right. My idea with the limit was to make the header safe to expose to untrusted clients but that makes it less useful. Also, it might never be totally safe because setting a 1s timeout could force some queries to fail and flood logs on the server.
So this header should fall in the same category as prefer:tx and Accept: application/vnd.pgrst.plan, it can only be exposed to trusted users.
This means it should be gated by a config and that we should remove the statement_timeout limit.
Thoughts?
To expose this header to an untrusted network, a similar thing to https://docs.postgrest.org/en/latest/references/observability.html#securing-the-execution-plan could be used.
There was a problem hiding this comment.
Who would want to set the timeout header to a value less than the role setting? What for?
In way this would be similar to soft and hard limits in Linux, set via ulimit. You can vary the soft limit on your own as long as you stay below the hard limit. Just because there is some higher limit available doesn't mean that you will always make full use of it.
I think it only really becomes useful when you have both:
- a low default for the soft limit, which you can override per request, and
- a higher hard limit
IIUC, we currently only have the limit defaulting to the hard limit, which then becomes the odd case of "you can only lower your limit".
Edit: This specifically only answers this question - I'm not saying we should implement any of this and also made no judgement on the PR or the related issue.
There was a problem hiding this comment.
Who would want to set the timeout header to a value less than the role setting? What for?
In way this would be similar to soft and hard limits in Linux, set via
ulimit.
To be honest, I always had a problem with understanding the purpose of soft limits. The only sensible use case IMHO is "grace periods" - ie. exceeding soft limit triggers a warning and requires a corrective action in a specified time period. But that really only makes sense for disk quotas etc. (and is not exactly the use case of user-provided limit).
Our situation is: a user has a query to run. The query will take x seconds to execute or will fail if the limit is lower. As a user I want to make sure my query does not fail so the only sensible strategy (as I don't know how long it will take) is not to set any limit by myself (and deal with possibility that system enforced limit is lower).
Of course - we could implement tracking of resource usage (per user? per tenant?) and have a policy like allow 10 queries above soft limit per month - but I don't think we want to do that :)
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.