Libra-1995 commited on
Commit
80f84b3
·
1 Parent(s): cfbf272

feat: add submission lock

Browse files
Files changed (3) hide show
  1. competitions/app.py +24 -16
  2. competitions/utils.py +5 -64
  3. requirements.txt +1 -0
competitions/app.py CHANGED
@@ -15,6 +15,7 @@ from huggingface_hub.utils._errors import EntryNotFoundError
15
  from loguru import logger
16
  from pydantic import BaseModel
17
  from requests.exceptions import RequestException
 
18
 
19
  from competitions import __version__, utils
20
  from competitions.errors import AuthenticationError, PastDeadlineError, SubmissionError, SubmissionLimitError
@@ -24,6 +25,8 @@ from competitions.oauth import attach_oauth
24
  from competitions.runner import JobRunner
25
  from competitions.submissions import Submissions
26
  from competitions.text import SUBMISSION_SELECTION_TEXT, SUBMISSION_TEXT
 
 
27
 
28
 
29
  HF_TOKEN = os.environ.get("HF_TOKEN", None)
@@ -298,22 +301,26 @@ def new_submission(
298
  if not utils.is_user_admin(user_token, comp_org):
299
  return {"response": "Competition has not started yet!"}
300
 
301
- competition_info = CompetitionInfo(competition_id=COMPETITION_ID, autotrain_token=HF_TOKEN)
302
- sub = Submissions(
303
- end_date=competition_info.end_date,
304
- submission_limit=competition_info.submission_limit,
305
- competition_id=COMPETITION_ID,
306
- token=HF_TOKEN,
307
- competition_type=competition_info.competition_type,
308
- hardware=competition_info.hardware,
309
- )
310
  try:
311
- if competition_info.competition_type == "generic":
312
- resp = sub.new_submission(user_token, submission_file, submission_comment)
313
- return {"response": f"Success! You have {resp} submissions remaining today."}
314
- if competition_info.competition_type == "script":
315
- resp = sub.new_submission(user_token, hub_model, submission_comment)
316
- return {"response": f"Success! You have {resp} submissions remaining today."}
 
 
 
 
 
 
 
 
 
 
317
  except RequestException:
318
  return {"response": "Hugging Face Hub is unreachable, please try again later"}
319
  except AuthenticationError:
@@ -324,7 +331,8 @@ def new_submission(
324
  return {"response": "Invalid submission file"}
325
  except SubmissionLimitError:
326
  return {"response": "Submission limit reached"}
327
- return {"response": "Invalid competition type"}
 
328
 
329
 
330
  @app.post("/update_selected_submissions", response_class=JSONResponse)
 
15
  from loguru import logger
16
  from pydantic import BaseModel
17
  from requests.exceptions import RequestException
18
+ from filelock import FileLock, Timeout as FileLockTimeout
19
 
20
  from competitions import __version__, utils
21
  from competitions.errors import AuthenticationError, PastDeadlineError, SubmissionError, SubmissionLimitError
 
25
  from competitions.runner import JobRunner
26
  from competitions.submissions import Submissions
27
  from competitions.text import SUBMISSION_SELECTION_TEXT, SUBMISSION_TEXT
28
+ from competitions.utils import team_file_api, submission_api
29
+ from competitions.enums import SubmissionStatus
30
 
31
 
32
  HF_TOKEN = os.environ.get("HF_TOKEN", None)
 
301
  if not utils.is_user_admin(user_token, comp_org):
302
  return {"response": "Competition has not started yet!"}
303
 
304
+ team_id = team_file_api.get_team_info(user_token)["id"]
305
+
306
+ lock = FileLock(f"./submission_lock/{team_id}.lock", blocking=False)
 
 
 
 
 
 
307
  try:
308
+ with lock:
309
+ if submission_api.count_by_status(team_id, [SubmissionStatus.QUEUED, SubmissionStatus.PENDING, SubmissionStatus.PROCESSING]) > 0:
310
+ return {"response": "Another submission is being processed. Please wait a moment."}
311
+ competition_info = CompetitionInfo(competition_id=COMPETITION_ID, autotrain_token=HF_TOKEN)
312
+ sub = Submissions(
313
+ end_date=competition_info.end_date,
314
+ submission_limit=competition_info.submission_limit,
315
+ competition_id=COMPETITION_ID,
316
+ token=HF_TOKEN,
317
+ competition_type=competition_info.competition_type,
318
+ hardware=competition_info.hardware,
319
+ )
320
+ if competition_info.competition_type == "script":
321
+ resp = sub.new_submission(user_token, hub_model, submission_comment)
322
+ return {"response": f"Success! You have {resp} submissions remaining today."}
323
+ return {"response": "Invalid competition type"}
324
  except RequestException:
325
  return {"response": "Hugging Face Hub is unreachable, please try again later"}
326
  except AuthenticationError:
 
331
  return {"response": "Invalid submission file"}
332
  except SubmissionLimitError:
333
  return {"response": "Submission limit reached"}
334
+ except FileLockTimeout:
335
+ return {"response": "Another submission is being processed. Please wait a moment."}
336
 
337
 
338
  @app.post("/update_selected_submissions", response_class=JSONResponse)
competitions/utils.py CHANGED
@@ -189,70 +189,6 @@ def delete_space(params):
189
  api.delete_repo(repo_id=os.environ["SPACE_ID"], repo_type="space")
190
 
191
 
192
- def download_submission_info(params):
193
- user_fname = hf_hub_download(
194
- repo_id=params.competition_id,
195
- filename=f"submission_info/{params.team_id}.json",
196
- token=params.token,
197
- repo_type="dataset",
198
- )
199
- with open(user_fname, "r", encoding="utf-8") as f:
200
- user_submission_info = json.load(f)
201
-
202
- return user_submission_info
203
-
204
-
205
- def upload_submission_info(params, user_submission_info):
206
- user_submission_info_json = json.dumps(user_submission_info, indent=4)
207
- user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
208
- user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
209
- api = HfApi(token=params.token)
210
- api.upload_file(
211
- path_or_fileobj=user_submission_info_json_buffer,
212
- path_in_repo=f"submission_info/{params.team_id}.json",
213
- repo_id=params.competition_id,
214
- repo_type="dataset",
215
- )
216
-
217
-
218
- def update_submission_status(params, status):
219
- user_submission_info = download_submission_info(params)
220
- for submission in user_submission_info["submissions"]:
221
- if submission["submission_id"] == params.submission_id:
222
- submission["status"] = status
223
- break
224
- upload_submission_info(params, user_submission_info)
225
-
226
-
227
- def update_submission_score(params, public_score, private_score):
228
- user_submission_info = download_submission_info(params)
229
- for submission in user_submission_info["submissions"]:
230
- if submission["submission_id"] == params.submission_id:
231
- submission["public_score"] = public_score
232
- submission["private_score"] = private_score
233
- submission["status"] = "done"
234
- break
235
- upload_submission_info(params, user_submission_info)
236
-
237
-
238
- def monitor(func):
239
- def wrapper(*args, **kwargs):
240
- params = kwargs.get("params", None)
241
- if params is None and len(args) > 0:
242
- params = args[0]
243
-
244
- try:
245
- return func(*args, **kwargs)
246
- except Exception as e:
247
- error_message = f"""{func.__name__} has failed due to an exception: {traceback.format_exc()}"""
248
- logger.error(error_message)
249
- logger.error(str(e))
250
- update_submission_status(params, SubmissionStatus.FAILED.value)
251
- pause_space(params)
252
-
253
- return wrapper
254
-
255
-
256
  def uninstall_requirements(requirements_fname):
257
  if os.path.exists(requirements_fname):
258
  # read the requirements.txt
@@ -583,6 +519,11 @@ class SubmissionApi:
583
  submission["status"] = status
584
  break
585
  self.upload_submission_info(team_id, user_submission_info)
 
 
 
 
 
586
 
587
 
588
  submission_api = SubmissionApi(
 
189
  api.delete_repo(repo_id=os.environ["SPACE_ID"], repo_type="space")
190
 
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  def uninstall_requirements(requirements_fname):
193
  if os.path.exists(requirements_fname):
194
  # read the requirements.txt
 
519
  submission["status"] = status
520
  break
521
  self.upload_submission_info(team_id, user_submission_info)
522
+
523
+ def count_by_status(self, team_id: str, status_list: List[SubmissionStatus]) -> int:
524
+ user_submission_info = self.download_submission_info(team_id)
525
+ count = sum(1 for submission in user_submission_info["submissions"] if SubmissionStatus(submission["status"]) in status_list)
526
+ return count
527
 
528
 
529
  submission_api = SubmissionApi(
requirements.txt CHANGED
@@ -15,3 +15,4 @@ gradio==4.37.2
15
  authlib==1.3.1
16
  itsdangerous==2.2.0
17
  hf-transfer
 
 
15
  authlib==1.3.1
16
  itsdangerous==2.2.0
17
  hf-transfer
18
+ filelock>=3.17.0