def pick_recruiter(self): """Pick the next recruiter to use. We use the `Recruitment` table in the db to keep track of how many recruitments have been requested using each recruiter. We'll use the first one from the specification that hasn't already reached its quota. """ counts = dict( session.query(Recruitment.recruiter_id, func.count( Recruitment.id)).group_by(Recruitment.recruiter_id).all()) for recruiter_id, target_count in self.spec: count = counts.get(recruiter_id, 0) if count >= target_count: # This recruiter quota was reached; # move on to the next one. counts[recruiter_id] = count - target_count continue else: # Quota is still available; let's use it. break else: raise Exception('Reached quota for all recruiters. ' 'Not sure which one to use now.') # record the recruitment session.add(Recruitment(recruiter_id=recruiter_id)) # return an instance of the recruiter return by_name(recruiter_id)
def recruiters(self, n=1): """Iterator that provides recruiters along with the participant count to be recruited for up to `n` participants. We use the `Recruitment` table in the db to keep track of how many recruitments have been requested using each recruiter. We'll use the first one from the specification that hasn't already reached its quota. """ recruit_count = 0 while recruit_count <= n: counts = dict( session.query(Recruitment.recruiter_id, func.count(Recruitment.id)).group_by( Recruitment.recruiter_id).all()) for recruiter_id, target_count in self.spec: remaining = 0 count = counts.get(recruiter_id, 0) if count >= target_count: # This recruiter quota was reached; # move on to the next one. counts[recruiter_id] = count - target_count continue else: # Quota is still available; let's use it. remaining = target_count - count break else: return num_recruits = min(n - recruit_count, remaining) # record the recruitments and commit for i in range(num_recruits): session.add(Recruitment(recruiter_id=recruiter_id)) session.commit() recruit_count += num_recruits yield by_name(recruiter_id), num_recruits