@@ -18,52 +18,45 @@ def __str__(self) -> str:
18
18
)
19
19
20
20
21
- def create_assignment (escrow_address : str , chain_id : Networks , wallet_address : str ) -> str | None : # noqa: ARG001 (don't we want to use chain_id for filter?)
21
+ def create_assignment (escrow_address : str , chain_id : Networks , wallet_address : str ) -> str | None :
22
22
with SessionLocal .begin () as session :
23
23
user = get_or_404 (
24
24
cvat_service .get_user_by_id (session , wallet_address , for_update = True ),
25
25
wallet_address ,
26
26
"user" ,
27
27
)
28
28
29
- # There can be several projects under one escrow, we need any
30
- project = cvat_service .get_project_by_escrow_address (
29
+ if cvat_service .has_active_user_assignments (
31
30
session ,
32
- escrow_address ,
33
- status_in = [
34
- ProjectStatuses .annotation
35
- ], # avoid unnecessary locking on completed projects
36
- for_update = True ,
37
- )
38
-
39
- if not project :
40
- # Retry without a lock to check if the project doesn't exist
41
- get_or_404 (
42
- cvat_service .get_project_by_escrow_address (
43
- session , escrow_address , status_in = [ProjectStatuses .annotation ]
44
- ),
45
- escrow_address ,
46
- "job" ,
47
- )
48
- return None
49
-
50
- has_active_assignments = (
51
- cvat_service .count_active_user_assignments (
52
- session , wallet_address = wallet_address , cvat_projects = [project .cvat_id ]
53
- )
54
- > 0
55
- )
56
- if has_active_assignments :
31
+ wallet_address = wallet_address ,
32
+ escrow_address = escrow_address ,
33
+ chain_id = chain_id .value ,
34
+ ):
57
35
raise UserHasUnfinishedAssignmentError (
58
36
"The user already has an unfinished assignment in this project"
59
37
)
60
38
39
+ # TODO: Try to put into 1 request. SQLAlchemy generates 2 queries with simple
40
+ # .options(selectinload(Job.project))
41
+ project = get_or_404 (
42
+ cvat_service .get_project_by_escrow_address (
43
+ session , escrow_address , status_in = [ProjectStatuses .annotation ]
44
+ ),
45
+ escrow_address ,
46
+ "job" ,
47
+ )
48
+
61
49
unassigned_job = cvat_service .get_free_job (
62
50
session ,
63
- cvat_projects = [project .cvat_id ],
51
+ escrow_address = escrow_address ,
52
+ chain_id = chain_id .value ,
64
53
user_wallet_address = wallet_address ,
65
54
for_update = True ,
55
+ # lock the job to be able to make a rollback if CVAT requests fail
56
+ # can potentially be optimized to make less DB requests
57
+ # and rely only on assignment expiration
66
58
)
59
+
67
60
if not unassigned_job :
68
61
return None
69
62
@@ -72,7 +65,12 @@ def create_assignment(escrow_address: str, chain_id: Networks, wallet_address: s
72
65
wallet_address = user .wallet_address ,
73
66
cvat_job_id = unassigned_job .cvat_id ,
74
67
expires_at = utcnow ()
75
- + timedelta (seconds = get_default_assignment_timeout (TaskTypes (project .job_type ))),
68
+ + timedelta (
69
+ seconds = get_default_assignment_timeout (
70
+ TaskTypes (project .job_type )
71
+ # TODO: need to update this if we have multiple job types per escrow
72
+ )
73
+ ),
76
74
)
77
75
78
76
cvat_service .touch (session , Job , [unassigned_job .id ])
0 commit comments