Skip to content

Downloads: only one transcode/convert job is sent to the server at a time, so queued batches don't render while the app is suspended #414

Open

Description

@jlipworth

Problem

With the downloads overhaul (P4, #385), Plex optimize / Emby Convert jobs go through a server-preparation admission lane capped at 1 (DownloadAdmissionLimits: .serverPreparation: 1, regardless of the simultaneous-downloads setting).

The handoff from "render finished" to "start the byte transfer" is app-side polling, which cannot run while the app is suspended (documented in docs/DOWNLOADS-OFFLINE.md). With the cap at 1, the only job the server knows about is the first one:

  1. The user queues three transcoded downloads and locks the phone / puts it away overnight.
  2. Only job 1 is sent to the server. It renders, but the app is suspended, so nothing notices and nothing downloads.
  3. Jobs 2 and 3 stay as Waiting for a download slot… and are never sent to the server.
  4. On opening the app, the poller sees job 1 ready, hands it to the static lane, and only then sends job 2. Job 3 waits again for job 2's render to be seen while the app is awake.

Net effect: a batch queued before bed gets at most one item prepared overnight. Reported on build 1537 (iOS); the cap is cross-platform.

Before the overhaul, single taps submitted their server job right away, so this is a regression in practice.

Expected

Queuing N transcoded downloads submits all N jobs to the server straight away, so the server can render them while the app is suspended. The server's own transcoder settings (for example Plex's background-transcode limit) decide how many render at once. When the app next runs, every finished render hands off to the static lane, subject to the static/total caps.

Proposed direction

  • Stop capping server submission at 1. Either remove .serverPreparation from the total/lane window, or give it a separate, larger submission cap (for example the total setting, or a fixed bound such as 5–10) that does not count against the transfer slots.
  • Keep the static-lane and total caps for byte transfers. A finished render that finds the static lane full waits as prepared, not as unsubmitted.
  • Pollers for every submitted job run whenever the app is awake, including on background-session wakes.
  • Pause, delete and sign-out keep cancelling each row's server job (D2), now for several rows at once.
  • Emby Convert: confirm that several concurrent Convert jobs are accepted, or keep a lower Emby-specific bound.

Acceptance

  • Unit: queuing 3 Plex optimize rows with total = 3 submits 3 server jobs without waiting for a handoff.
  • Unit: renders that finish while the static lane is full wait without resubmitting, and start in request order.
  • Unit: delete or pause of a submitted-but-unrendered row cancels its server job.
  • Docs: DOWNLOADS-OFFLINE.md admission section updated.
  • Device (user): queue 3 transcoded downloads, background for several hours, reopen; all 3 renders are complete server-side and the transfers start.

Activity

  1. jlipworth commented on Oct 18, 2026

    @jlipworth
    OwnerAuthor

    Implemented on downloads/overhaul (2bfe90d, 4749f0a, 25bc691) and included in TestFlight internal 1.8.0 (build 1541).

    • Server preparation has its own fixed bound of 5 jobs and no longer uses a transfer slot, so every queued Plex optimize or Emby Convert job is submitted to the server straight away. The server's transcoder settings decide how many render at once.
    • A finished render keeps its prep slot and reads Ready — waiting for a download slot… until the static and total transfer caps have room. It then starts with the live backend session. Waiting renders go first come, first served, ahead of new transfer starts.
    • A Plex render found finished after its 24-hour render deadline is now adopted rather than failed. That covers a render that waited for a slot and was then rediscovered after a relaunch.
    • An Emby start that reuses an already converted version (so there's no job identity yet) still hands off at once, as before.
    • Correction to the acceptance list above: pause keeps the server job so Resume reuses the render (existing behavior); delete cleans it up (D2).

    Checks: GPT-6.1-Sol plan co-review plus two implementation review rounds (approved). PMSKit (Linux and Mac), all four platform builds, iPhone hosted (932 + 66), Mac hosted (945 + 66), iPhone UI smoke, visionOS smoke and hygiene are green. New tests include the real Plex and Emby executor handoff paths and a relaunch-past-deadline regression; I confirmed the regression test fails without the fix.

    Device acceptance is still open: queue three transcoded downloads, background the device for a few hours, and confirm all three render and then transfer within the simultaneous-downloads setting.

  2. jlipworth commented on Nov 5, 2026

    @jlipworth
    OwnerAuthor

    Landed on main in #425 (0b7f3fcb, tag v1.8.0). Any device or live acceptance gate already noted here still applies; the issue stays open until it's checked.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions