Skip to content

Sort offers by price within availability groups in _get_job_plan#3840

Open
megheaiulian wants to merge 1 commit intodstackai:masterfrom
plumelo:fix-3839-offer-sort-by-price
Open

Sort offers by price within availability groups in _get_job_plan#3840
megheaiulian wants to merge 1 commit intodstackai:masterfrom
plumelo:fix-3839-offer-sort-by-price

Conversation

@megheaiulian
Copy link
Copy Markdown

@megheaiulian megheaiulian commented Apr 30, 2026

Summary

Fixes #3839

_get_job_plan() sorted offers only by availability (not offer.availability.is_available()), preserving the input order from heapq.merge. Since backend offers are not guaranteed to be price-sorted (gpuhunt explicitly documents its results as "not strictly sorted by the price"), cheap offers from one backend (e.g., Vast.ai at $0.37) could be buried behind expensive offers from another backend (e.g., RunPod at $0.98).

This was the root cause of #3839: dstack apply showed RunPod offers ($0.98+) before cheaper Vast.ai offers ($0.37+), while dstack offer correctly sorted by price because it uses get_backend_offers_in_run_candidate_fleets() which explicitly sorts by price.

Changes

  • plan.py:835: Add offer.price as secondary sort key so that within each availability group, offers are sorted cheapest-first:

    # Before:
    job_offers.sort(key=lambda offer: not offer.availability.is_available())
    # After:
    job_offers.sort(key=lambda offer: (not offer.availability.is_available(), offer.price))
  • test_plan.py: Add TestGetJobPlan with 5 tests:

    • test_sorts_available_offers_by_price — available offers sorted by price even when input is out of order
    • test_sorts_not_available_offers_by_price — NOT_AVAILABLE offers also sorted by price
    • test_sorts_mixed_availability_by_availability_then_price — available group sorted by price, then NOT_AVAILABLE group sorted by price (inputs in reverse price order to verify sort, not just stable order)
    • test_sorts_unsorted_multi_backend_offers_by_price — reproduces the bug: RunPod offers ($0.98, $1.49) before Vast.ai ($0.37, $1.22) in input, verifying price sort produces correct order
    • test_instance_offers_and_backend_offers_sorted_by_availability_then_price — expensive IDLE pool instance ($0.98) sorts after cheap AVAILABLE backend offer ($0.37)

How to test

dstack apply -f service.yaml --max-offers 300

Before: RunPod offers ($0.98+) appear before cheaper Vast.ai offers ($0.37+)
After: All offers sorted by price ascending within availability groups

…ackai#3839)

The sort in _get_job_plan only sorted by availability, preserving the
input order from heapq.merge. Since backend offers are not guaranteed to
be price-sorted (gpuhunt explicitly documents its results as 'not strictly
sorted by the price'), cheap offers from one backend could be buried
behind expensive offers from another.

Add price as a secondary sort key so that available offers are sorted
cheapest-first, matching the behavior of the dstack offer path which
explicitly sorts by price in get_backend_offers_in_run_candidate_fleets.
@megheaiulian megheaiulian force-pushed the fix-3839-offer-sort-by-price branch from f491338 to ff46674 Compare April 30, 2026 14:45
if profile.creation_policy == CreationPolicy.REUSE_OR_CREATE:
job_offers.extend(offer for _, offer in backend_offers)
job_offers.sort(key=lambda offer: not offer.availability.is_available())
job_offers.sort(key=lambda offer: (not offer.availability.is_available(), offer.price))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If I'm not mistaken, sorting here:

  • Only affects the run plan shown in dstack apply, but doesn't affect the actual provisioning order.
  • Can shuffle the available instance_offers (representing idle instances) and backend_offers (representing new instances to be provisioned), which is not expected — idle instances should always come first regardless of the price, as dstack prefers reusing them over provisioning new ones.

Anyways, I'm not sure if we want to sort by price in the first place, please see my issue comment

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.

offers not sorted by price in dstack apply plan — cheap offers hidden behind expensive ones

2 participants