Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions queue_environments/windows_path_limit_junction_fix.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
specificationVersion: 'environment-2023-09'
parameterDefinitions:
- name: JunctionPath
type: STRING
default: 'C:\tmp\dc-root'
description: >
The short path where the junction will be created. This path will point to
the session's assetroot folder, allowing applications with MAX_PATH limitations
(such as After Effects) to access files through a shorter path.
environment:
name: Assetroot Junction Creation
description: |
Creates a Windows directory junction from a short configurable path to the
session's assetroot folder, and sets the DEADLINE_ASSETROOT_ALIAS environment
variable so that compatible job scripts can rewrite file paths through the
junction.

This works around the Windows MAX_PATH (260 character) limitation for
applications that use legacy Win32 APIs (e.g. Adobe After Effects, Cinema4D).

The junction is removed when the session ends.

This queue environment is only effective on Windows workers. On non-Windows
workers the onEnter script exits successfully without creating a junction.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The description promises that "on non-Windows workers the onEnter script exits successfully without creating a junction," but nothing in the script implements that guard. command: powershell invokes Windows PowerShell, which does not exist on Linux/macOS workers, so the onEnter action will fail to launch (or, if pwsh were used, cmd /c mklink would fail) rather than exiting 0. Either add an early OS check that exits successfully on non-Windows (e.g. if (-not $IsWindows) { exit 0 }), or adjust the description so it does not claim graceful non-Windows behavior. As written the environment will error the session on any non-Windows worker.

script:
actions:
onEnter:
command: powershell
args:
- "{{Env.File.Enter}}"
onExit:
command: powershell
args:
- "{{Env.File.Exit}}"
embeddedFiles:
- name: Enter
filename: junction-enter.ps1
type: TEXT
data: |
$ErrorActionPreference = 'Stop'
$junctionPath = '{{Param.JunctionPath}}'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

JunctionPath is a single fixed location (default C:\tmp\dc-root), but a Deadline Cloud worker can run multiple sessions concurrently. Two sessions using this environment will fight over the same junction: the second onEnter deletes the first session's junction (via the "remove stale junction" block) and repoints C:\tmp\dc-root at its own assetroot, so the first session's DEADLINE_ASSETROOT_ALIAS now silently resolves to the wrong assetroot. Worse, whichever session exits first removes the junction out from under the still-running session. Consider making the junction path unique per session (e.g. append a short session-derived suffix) so concurrent sessions do not corrupt each other's asset paths, or document that this environment is only safe on single-session fleets.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A worker can run multiple sessions concurrently??


# Ensure parent directory exists
$parentDir = Split-Path $junctionPath -Parent
if (!(Test-Path $parentDir)) {
New-Item -ItemType Directory -Path $parentDir | Out-Null
}

# Remove stale junction if it exists
if (Test-Path $junctionPath) {
cmd /c "rmdir $junctionPath"
if (Test-Path $junctionPath) {
Write-Error "Failed to remove stale junction at $junctionPath"
exit 1
}
}

# Find the assetroot folder in the session working directory
$sessionDir = $PWD.Path
$assetroot = Get-ChildItem $sessionDir -Directory | Where-Object { $_.Name -like 'assetroot-*' } | Select-Object -First 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This assumes a single assetroot folder and blindly takes Select-Object -First 1. A session can have more than one assetroot-* folder (multiple input path mappings / storage profile locations). When that happens, only one is aliased and jobs referencing paths under the other assetroots will resolve incorrectly through the junction. The selection is also order-dependent (whatever Get-ChildItem returns first), so which assetroot wins is not deterministic. Consider handling the multi-assetroot case explicitly, or at least documenting the single-assetroot assumption.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will address tomorrow

if (!$assetroot) {
Write-Error "No assetroot folder found in session directory: $sessionDir"
exit 1
}

# Create junction
$result = cmd /c "mklink /J $junctionPath $($assetroot.FullName)" 2>&1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The path arguments to cmd /c are not quoted, so any space in $junctionPath or in the assetroot path will break these commands. mklink /J C:\my dir\dc-root C:\...\assetroot-123 parses as multiple arguments and fails; the same applies to rmdir $junctionPath on lines 51 and 83. The JunctionPath default is space-free, but a user can override it, and session working directories can contain spaces. Quote the paths inside the cmd /c string, e.g. cmd /c "mklink /J "$junctionPath" "$($assetroot.FullName)"" (and likewise rmdir "...").

if (!(Test-Path $junctionPath)) {
Write-Error "Failed to create junction: $result"
exit 1
}

Write-Host "Junction created: $junctionPath -> $($assetroot.FullName)"

# Set the environment variable for downstream job scripts
Write-Host "openjd_env: DEADLINE_ASSETROOT_ALIAS=$junctionPath"
- name: Exit
filename: junction-exit.ps1
type: TEXT
data: |
$junctionPath = '{{Param.JunctionPath}}'
if (Test-Path $junctionPath) {
cmd /c "rmdir $junctionPath"
Write-Host "Junction removed: $junctionPath"
}
Loading