Skip to content

Dequeue atomic - #290

Open
AlbertoCasasOrtiz wants to merge 8 commits into
devfrom
dequeue-atomic
Open

Dequeue atomic#290
AlbertoCasasOrtiz wants to merge 8 commits into
devfrom
dequeue-atomic

Conversation

@AlbertoCasasOrtiz

Copy link
Copy Markdown
Member

Fixes #267.

Most changes are due to indentation. Real changes are the addition of atomic to make everything a single transaction:

with transaction.atomic():

Select for update, which locks the trial so other workers cannot modify or lock them. If already locked by another worker, it skips it.

.select_for_update(skip_locked=True)

And a status check that, if for any reason a worker gets a trial already locked and in a non-available status, will skip it:

if trial.status not in ["stopped", "reprocess"]:
    raise Http404

@AlbertoCasasOrtiz AlbertoCasasOrtiz changed the title WIP - Dequeue atomic Dequeue atomic Jun 30, 2026
@AlbertoCasasOrtiz

Copy link
Copy Markdown
Member Author

@carmichaelong I just fixed conflicts on this branch

@carmichaelong
carmichaelong requested a review from csherry04 July 30, 2026 21:41
Comment thread mcserver/views.py Outdated
Comment on lines 1667 to 1703

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlbertoCasasOrtiz It looks like maybe this second section got copied in with merge but it reassigning the things just assigned in the atomic transaction. The second version (not atomic) seems to maybe be the one with updated logic for the delayed uploads? Perhaps then can get rid of the first one and wrap the second one in an atomic transaction?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @csherry04. I just updated it accordingly (to avoid conflicts with dev and duplicated code, I modified from original code again to be atomic).

@AlbertoCasasOrtiz

Copy link
Copy Markdown
Member Author

I just created a new test for this. Also, changed some database calls to be more efficient.

@carmichaelong carmichaelong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @AlbertoCasasOrtiz. I've left some comments throughout. Happy to chat about strategies to address too if that's helpful some time.

Two other thoughts about the tests:

  • Less related to this PR specifically but more generally for growing the tests, might be helpful to add a different test to make sure dequeue() returns the correct status codes under different conditions.
  • If you choose to add the suggestion to order trials, could be good to add a test to make sure the order in which they are dequeue'ed is correct.

Comment thread mcserver/views.py
trial = trialsPrioritized.select_for_update(
skip_locked=True,
of=("self",)
).first()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously this used [0] to grab the first trial which would be caught and raise APIException which returns a 500 status code, which is handled in app.py.

Now, first() is used which can return None, and go down a different branch and return a 200 status code, which isn't handled yet.

This would slightly change the logic, but I'd suggest if first() returns None, perhaps we should also raise a 404 like above.

Comment thread mcserver/views.py
if not trials.exists():
trialsPrioritized = trialsReprocess

trial = trialsPrioritized.select_for_update(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be good to make sure this is ordered, perhaps by created_at (rather than updated_at)? Open to ideas of what might work best here.

if response.status_code == 200:
results['worker1'] = response.data.get('id')
else:
results[

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo with a new line?

return original_save(self_instance, *args, **kwargs)

try:
with patch('mcserver.models.Trial.save', new=delayed_save):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

patch() changes the object globally. Along with the wait time in delayed_save(), this likely affects worker 2's save() as well, which then may wait so long that worker 1 may not be in stopped state anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants