-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(HMS-1783): allow 2 reservations in one second
- Loading branch information
Showing
4 changed files
with
54 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
-- | ||
-- Function (and trigger) for throttling reservations. AWS does not allow more launches per account that 2 per second | ||
-- (with the initial bucket set to 5). This prevents from launching more than 2 instances per second for an individual | ||
-- account. It is applied on all hyperscalers despite other clouds might have different limits. | ||
-- | ||
-- Enforcement on the database level seems to be the most efficient way of throttling down clients, in-app solution | ||
-- would need to have a shared place (e.g. Redis) for storing state. This solution is also transactional safe. | ||
-- Error generated by this function is returned in the error payload to the user or UI. | ||
-- | ||
-- A side effect of this solution is that there can be gaps in the primary key sequence which is not a problem at all. | ||
-- | ||
|
||
-- Actual reservation limit per account and provider type (returns constant number) | ||
CREATE OR REPLACE FUNCTION reservations_rate_limit() RETURNS INTEGER AS | ||
$reservations_rate_limit$ | ||
BEGIN | ||
RETURN 5; | ||
END; | ||
$reservations_rate_limit$ LANGUAGE plpgsql; | ||
|
||
-- Rate limiting function (throws exception when exceeded) | ||
CREATE FUNCTION reservations_rate() RETURNS TRIGGER AS | ||
$reservations_rate$ | ||
DECLARE | ||
maximum INTEGER := reservations_rate_limit(); | ||
last_rec RECORD; | ||
BEGIN | ||
FOR last_rec IN SELECT COUNT(*) FROM reservations WHERE account_id = NEW.account_id AND provider = NEW.provider AND success IS NULL AND created_at >= now() - INTERVAL '1 second' | ||
LOOP | ||
IF last_rec.count >= maximum THEN | ||
RAISE EXCEPTION 'too many pending reservations (%) for this provider (maximum % per second)', last_rec.count, maximum; | ||
END IF; | ||
END LOOP; | ||
|
||
RETURN NEW; | ||
END; | ||
$reservations_rate$ LANGUAGE plpgsql; | ||
|
||
-- Rate limiting trigger | ||
CREATE TRIGGER reservations_rate_trigger | ||
BEFORE INSERT ON reservations | ||
FOR EACH ROW | ||
EXECUTE FUNCTION reservations_rate(); | ||
|
||
CREATE INDEX reservations_created_at_idx ON reservations(created_at); |