@@ -278,11 +278,16 @@ def create_submission(
278278 time : datetime .datetime ,
279279 user_name : str = None ,
280280 mode_category : str = None ,
281+ requested_gpus : Optional [list [str ] | str ] = None ,
281282 ) -> Optional [int ]:
282283 try :
283284 if time .tzinfo is None :
284285 time = time .astimezone ()
285286 time = time .astimezone (datetime .timezone .utc )
287+ if requested_gpus is None :
288+ requested_gpus = []
289+ elif isinstance (requested_gpus , str ):
290+ requested_gpus = [requested_gpus ]
286291
287292 # check if we already have the code
288293 self .cursor .execute (
@@ -329,10 +334,10 @@ def create_submission(
329334 self .cursor .execute (
330335 """
331336 INSERT INTO leaderboard.submission (leaderboard_id, file_name,
332- user_id, code_id, submission_time, mode_category)
337+ user_id, code_id, submission_time, mode_category, requested_gpus )
333338 VALUES (
334339 (SELECT id FROM leaderboard.leaderboard WHERE name = %s),
335- %s, %s, %s, %s, %s)
340+ %s, %s, %s, %s, %s, %s )
336341 RETURNING id
337342 """ ,
338343 (
@@ -342,6 +347,7 @@ def create_submission(
342347 code_id ,
343348 time ,
344349 mode_category ,
350+ requested_gpus ,
345351 ),
346352 )
347353 submission_id = self .cursor .fetchone ()[0 ]
@@ -1778,6 +1784,40 @@ def check_rate_limit(
17781784 logger .exception ("Error checking rate limit" , exc_info = e )
17791785 raise KernelBotError ("Error checking rate limit" ) from e
17801786
1787+ def check_gpu_submission_rate_limit (
1788+ self , user_id : str , gpu_type : str , max_per_hour : int
1789+ ) -> dict :
1790+ """Check if a user has exceeded a per-GPU submission limit over the last hour."""
1791+ try :
1792+ self .cursor .execute (
1793+ """
1794+ SELECT COUNT(*), MIN(submission_time)
1795+ FROM leaderboard.submission
1796+ WHERE user_id = %s
1797+ AND requested_gpus @> ARRAY[%s]::TEXT[]
1798+ AND submission_time > NOW() - INTERVAL '1 hour'
1799+ """ ,
1800+ (str (user_id ), gpu_type ),
1801+ )
1802+ current_count , oldest_time = self .cursor .fetchone ()
1803+ allowed = current_count < max_per_hour
1804+ retry_after = 0
1805+ if not allowed and oldest_time is not None :
1806+ expiry = oldest_time + datetime .timedelta (hours = 1 )
1807+ now = datetime .datetime .now (datetime .timezone .utc )
1808+ retry_after = max (0 , int ((expiry - now ).total_seconds ()))
1809+
1810+ return {
1811+ "allowed" : allowed ,
1812+ "current_count" : current_count ,
1813+ "max_per_hour" : max_per_hour ,
1814+ "retry_after_seconds" : retry_after ,
1815+ }
1816+ except psycopg2 .Error as e :
1817+ self .connection .rollback ()
1818+ logger .exception ("Error checking GPU submission rate limit" , exc_info = e )
1819+ raise KernelBotError ("Error checking GPU submission rate limit" ) from e
1820+
17811821
17821822class LeaderboardDoesNotExist (KernelBotError ):
17831823 def __init__ (self , name : str ):
0 commit comments