feat: add Rez PATH-shim queue environment with tool auto-discovery - #270
Conversation
The existing rez_queue_env.yaml resolves Rez in a subshell during onEnter and then replays a before/after environment-variable diff via openjd_env. That flattening loses shell functions, aliases and ordered PATH edits, which is a known limitation for Rez users. This adds a queue environment that instead writes a small shim per Rez tool into the session directory and prepends it to PATH. Job templates keep calling tools by bare name, and each invocation re-enters the resolved Rez context in its own real shell. Tool names come from 'rez context -t' on the saved .rxt context, so no hard-coded list of DCC executables is needed. The RezExtraTools parameter covers commands a package provides but does not declare. Also adds a self-contained demo variant that installs Rez and builds a demo package in the session directory, plus a job bundle that verifies a tool's environment is visible inside the tool but never leaked into the session. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
Add the two new queue environments to the queue_environments index table with a section explaining why the shim approach exists and its tradeoffs, add the demo job bundle to the job_bundles index, and give the bundle a README following the repository sample template. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
The demo queue environment duplicated the whole shim mechanism, so the sample exercised a copy rather than the real environment and the two could drift. Replace it with rez_demo_setup_queue_env.yaml, which only installs Rez and builds a demo package. Attaching it before rez_queue_env_shim.yaml lets the demo use the real shim environment unmodified. Also remove Windows support from the shim environment. The shims are POSIX shell scripts relying on a shebang, which does not work on Windows, and it was never tested there. It now fails with a clear message pointing at rez_queue_env.yaml instead of silently writing shims that cannot run. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
The demo package only set environment variables, which the existing rez_queue_env.yaml carries correctly, so the sample did not demonstrate the problem it exists to explain. Add a Rez alias and a PATH prepend that shadows a system command to the demo package, and turn the verify step into three fidelity checks that fail the task on regression. Under rez_queue_env.yaml the session runtime rejects the alias assignment outright, which is the failure the shim environment avoids. Also capture command output before matching instead of piping into 'grep -q', which closes the pipe on first match and trips SIGPIPE under pipefail. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
State plainly who should choose the shim environment and why, replacing prose that described the mechanism before naming the problem. Reference the upstream Environment Wrap Actions RFC, which supersedes this workaround once it ships. Correct queue and fleet terminology: queues are platform agnostic, so the Linux and macOS constraint belongs to the fleet's workers. Drop the demo setup environment from the index table and link it from the shim section instead, since it is test scaffolding rather than a deployable sample. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
The shim environment, its test scaffolding, and the verification job are not independently useful, but they were split across queue_environments/ and job_bundles/ with a README each. Move all three under queue_environments/rez_shim/ and replace the two READMEs with one covering the whole set. The queue_environments and job_bundles index tables now point at the directory rather than listing the pieces separately, matching how nested collections are handled elsewhere in the repository. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
The tradeoff list claimed cancelation was untested and asserted that 'exec' keeps the process tree flat. The second half was wrong: Rez runs the tool in a shell of its own, so the tree is shim -> rez env -> shell -> tool. Signal delivery works anyway. Add a long-running demosleep tool that reports the signal it catches, plus a CancelThroughShim step to trigger it, and replace the untested-tradeoff bullet with the verified behavior. Confirmed on a Linux service-managed fleet worker: canceling the step logs 'INTERRUPT: Sending signal term' followed by 'demosleep: caught SIGTERM, exiting', with no orphans. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
Replace 'ships' with the specific verb, drop three uses of 'therefore', split a semicolon into two sentences, restructure a three-verb series, and name the noun behind a standalone 'This is'. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
A shim that re-invoked its tool by bare name relied on Rez rebuilding PATH from the resolved context and dropping the shim directory. That holds by default, but a farm whose Rez config lists PATH in parent_variables keeps the shim directory ahead of the package's own bin directory, so the shim found itself and forked until the worker ran out of processes. Reproduced with REZ_PARENT_VARIABLES=PATH: 60 processes in 15 seconds. Resolve each tool with 'command -v' inside the context when the shim is written and exec that absolute path. Tools resolving back into the shim directory, or unresolvable in the context, now get no shim and are reported at startup instead of failing confusingly at task time. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
Checks 2 and 3 read the resolved context directly with 'rez env --input', so they verified the .rxt file could be re-entered rather than that the shims and PATH injection worked. Deleting the PATH injection from the environment left both passing, and only check 1 caught the regression. Add a demoprobe tool that reports the alias and 'sort' resolution from inside a correctly applied context. Because it is a declared Rez tool it gets a shim, so calling it by bare name makes both checks depend on the shim mechanism end to end. With the PATH injection removed all three checks now fail. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
The comment told users to set a Windows repository path, carried over from rez_queue_env.yaml. This environment defines only LINUX_ and MACOS_ variables and fails immediately on Windows workers. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
| start, end = int(start_s), int(end_s) | ||
| else: | ||
| start = end = int(args.frame_range) | ||
| start_s, end_s = args.frame_range.split("-") |
There was a problem hiding this comment.
Removing the single-frame branch makes frame_range.split("-") crash on a single-value FrameRange.
FrameRange is a free-form LINE_EDIT STRING param and is also fed to the step as an OpenJD task range: "{{Param.FrameRange}}", which happily accepts a bare integer (e.g. FrameRange=5 to render one test frame). With this change, "5".split("-") returns ["5"] and the unpack start_s, end_s = args.frame_range.split("-") raises ValueError: not enough values to unpack. The task range stays valid, so OpenJD schedules the frame and the script then dies with a cryptic error instead of the previous graceful start = end = int(...).
The same removal in encode_movie.py and make_thumbnail.py has the identical failure mode. If single-frame ranges are meant to be unsupported now, consider validating FrameRange and emitting a clear message rather than letting the unpack throw.
Fixes: no issue yet — opening as a draft per CONTRIBUTING's "talk with us first" guidance, happy to file one if you'd prefer to track it there
What was the problem/requirement? (What/Why)
A customer reported that Rez does not work well with queue environments, because a queue environment runs in a single subprocess and the render command only receives environment variables harvested from it and replayed.
That is accurate, and it is structural rather than a bug. A queue environment action runs in its own subprocess, so the only channel into later actions is
openjd_env: NAME=valuedirectives. The existingrez_queue_env.yamltherefore activates a context, diffs the environment before and after, and replays the difference. Anything that is not a name-value pair does not survive.A Rez
aliasis the clearest casualty. Rez implements it as an exported shell function, which Bash exports under a name likeBASH_FUNC_launch%%with a multi-line value. The session runtime rejects that assignment outright:So the alias is gone before any task runs. Ordered
PATHedits are similarly fragile: the variable is restored, but a later environment that also editsPATHcan reorder it.What was the solution? (How)
A queue environment that wraps each task's command instead of exporting variables to it.
onEnterresolves the requested packages once, saves the context to a.rxtfile in the session directory, asks Rez which executables those packages provide, and writes one shim per tool with the shim directory prepended toPATH:Job templates keep calling tools by bare name, such as
command: mayapy, so each call re-enters the saved context in its own shell and Rez applies the full context inside the task's own process. Job bundles need no changes.Tool names come from
rez context -ton the saved context, so there is no hard-coded list of DCC executables.RezExtraToolscovers commands a package provides without declaring them in itstoolslist.This is a workaround for a specification gap, not a permanent design. RFC0008: Environment Wrap Actions proposes
onWrapTaskRun, which does this properly; once it ships in the worker agent, the wrap hook replaces the shim directory and thePATHmanipulation entirely. The README says so explicitly so nobody mistakes this for the intended long-term shape.What is the impact of this change?
Additive. Three new files under
queue_environments/rez_shim/, no changes to existing samples:rez_queue_env_shim.yamlrez_demo_setup_queue_env.yamldemo_job_bundle/template.yamlThe existing
rez_queue_env.yamlis untouched and remains the right choice when packages only set variables, and the only choice on Windows.Known tradeoffs, all documented in the README:
rez_queue_env.yaml. I deliberately did not claim Windows support, since it is not tested.How was this change tested?
Locally with
openjd run, and end to end on a Deadline Cloud farm with a Linux service-managed fleet (on-demand, 2–4 vCPU). All templates passopenjd check, andpython3 scripts/validate_repository.pypasses.The demo job proves its own thesis rather than asserting it.
VerifyEnvironmentruns three fidelity checks and fails the task on regression:aliasPATHprepend shipping its ownsortFarm run, on the worker under
job-user:UNSETin the session with1.0.0inside the tool is the core result: the variable was never harvested and replayed, Rez applied it inside the task's own process.Cancelation was verified too, since it is the obvious risk with a wrapper. Rez runs the tool in a shell of its own, so the tree is
shim→rez env→ shell → tool rather than flat, but signals still propagate. Canceling theCancelThroughShimstep on the farm:Task ended
CANCELEDwith no orphans, so an application with its own signal handler gets to shut down cleanly.Not tested: Windows (unsupported by design, guarded with a clear failure), and macOS workers on a real fleet — the macOS path was exercised locally only.
Was this change documented?
Yes. One README for the whole set at
queue_environments/rez_shim/README.md, covering when to choose this overrez_queue_env.yaml, why the simpler sample cannot cover those cases, deployment, parameters, tradeoffs, the upstream RFC, and cleanup. Thequeue_environmentsindex table points at the directory, matching how nested collections are handled elsewhere in the repo.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.