Background: this follows up on our earlier case [Content removed] where you confirmed that limiting Horde device reservation blocks to a single device was not intentional and would be fixed in a future release. It is still present in 5.8, ue5-main and ue6-main, so we have written a fix and opened a pull request: https://github.com/EpicGames/UnrealEngine/pull/15239
PROBLEM
A device reservation block (a step annotated DeviceReserve=Begin installs a build; later steps in the batch run with -SkipInstall on the same devices) only works with one device. With two devices the install step is given the same device twice (“Installing on 2: deviceA, deviceA”), so the build is installed twice on one devkit and the second devkit is never reserved. A later step that asks for one device gets both devices of the block back and fails.
CAUSE
HordeDeviceReservationService.ReserveDevicesFromService (Gauntlet.DeviceReservationService.cs) sends one reservation request per device and requires exactly one device back (DeviceReservation.Devices.Count != 1). Horde answers any request made from a step inside a reservation block with the block’s existing reservation (DeviceCollection.TryFindReserveBlockAsync), whatever was asked for.
FIX (PR #15239, one file, +56/-6, against ue5-main)
Grouped requests: constraints without an explicit DeviceName that share the same tags go in one reservation request, and the returned devices are paired with their constraints (by platform, otherwise in order). Named devices keep one request each. Outside a reservation block the result is the same as before: one request for N devices allocates what N single requests did.
Count check: it compares against the number of constraints in the request, and a failed request releases the reservations already made in that call.
Release: ReleaseDevices now uses the DisposeReservation value it already computes, so a shared reservation is released only with its last device.
TESTING
On Horde: a pool of two console devkits, an install step followed by several test steps. Before the fix, two requests and the same devkit twice; with the fix, one request, two different devkits, one install each, and every later step reused both devkits with -SkipInstall.
Locally: the unmodified and fixed service run against a local stand-in for the Horde device endpoints that applies the same reservation-block rule (9 scenarios: install step, follow-up step, one-device request inside a two-device block, different tags, named devices, no tags vs empty tags, shared-reservation release, failed registration, failed 409 request).
QUESTIONS
Question 1: Will you take this change (PR #15239)?
Question 2: Is ue5-main the right base for the PR, or would you rather have it against ue6-main? ue6-main has the same loop; there the new UpdateAndVerifyDeviceOSTags call needs to stay inside the per-device loop.
Question 3: If you already have a different fix planned or submitted, could you share the CL so we can backport it instead?
Thanks!
[Attachment Removed]