@@ -648,8 +648,10 @@ private async Task StartContainerAsync(IExecutionContext executionContext, Conta
648648 trace . Info ( $ "Configured { container . MountVolumes . Count } volume mounts: { string . Join ( ", " , mountSummary ) } ") ;
649649
650650 bool useNode20ToStartContainer = AgentKnobs . UseNode20ToStartContainer . GetValue ( executionContext ) . AsBoolean ( ) ;
651+ bool useNode24ToStartContainer = AgentKnobs . UseNode24ToStartContainer . GetValue ( executionContext ) . AsBoolean ( ) ;
651652 bool useAgentNode = false ;
652653
654+ string labelContainerStartupUsingNode24 = "container-startup-using-node-24" ;
653655 string labelContainerStartupUsingNode20 = "container-startup-using-node-20" ;
654656 string labelContainerStartupUsingNode16 = "container-startup-using-node-16" ;
655657 string labelContainerStartupFailed = "container-startup-failed" ;
@@ -662,6 +664,7 @@ string containerNodePath(string nodeFolder)
662664 string nodeContainerPath = containerNodePath ( NodeHandler . NodeFolder ) ;
663665 string node16ContainerPath = containerNodePath ( NodeHandler . Node16Folder ) ;
664666 string node20ContainerPath = containerNodePath ( NodeHandler . Node20_1Folder ) ;
667+ string node24ContainerPath = containerNodePath ( NodeHandler . Node24Folder ) ;
665668
666669 if ( container . IsJobContainer )
667670 {
@@ -697,9 +700,22 @@ string useDoubleQuotes(string value)
697700 else
698701 {
699702 useAgentNode = true ;
700- trace . Info ( $ "Using agent-provided Node.js. Node20 enabled: { useNode20ToStartContainer } ") ;
701- trace . Info ( $ "Node paths - Default: { nodeContainerPath } , Node16: { node16ContainerPath } , Node20: { node20ContainerPath } ") ;
702- string sleepCommand = useNode20ToStartContainer ? $ "'{ node20ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode20 } ' && { nodeSetInterval ( node20ContainerPath ) } || '{ node16ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode16 } ' && { nodeSetInterval ( node16ContainerPath ) } || echo '{ labelContainerStartupFailed } '" : nodeSetInterval ( nodeContainerPath ) ;
703+ trace . Info ( $ "Using agent-provided Node.js. Node20 enabled: { useNode20ToStartContainer } , Node24 enabled: { useNode24ToStartContainer } ") ;
704+ trace . Info ( $ "Node paths - Default: { nodeContainerPath } , Node16: { node16ContainerPath } , Node20: { node20ContainerPath } , Node24: { node24ContainerPath } ") ;
705+ string sleepCommand ;
706+
707+ if ( useNode24ToStartContainer )
708+ {
709+ sleepCommand = $ "'{ node24ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode24 } ' && { nodeSetInterval ( node24ContainerPath ) } || '{ node20ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode20 } ' && { nodeSetInterval ( node20ContainerPath ) } || '{ node16ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode16 } ' && { nodeSetInterval ( node16ContainerPath ) } || echo '{ labelContainerStartupFailed } '";
710+ }
711+ else if ( useNode20ToStartContainer )
712+ {
713+ sleepCommand = $ "'{ node20ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode20 } ' && { nodeSetInterval ( node20ContainerPath ) } || '{ node16ContainerPath } ' --version && echo '{ labelContainerStartupUsingNode16 } ' && { nodeSetInterval ( node16ContainerPath ) } || echo '{ labelContainerStartupFailed } '";
714+ }
715+ else
716+ {
717+ sleepCommand = nodeSetInterval ( nodeContainerPath ) ;
718+ }
703719 container . ContainerCommand = PlatformUtil . RunningOnWindows ? $ "cmd.exe /c call { useDoubleQuotes ( sleepCommand ) } " : $ "bash -c \" { sleepCommand } \" ";
704720 container . ResultNodePath = nodeContainerPath ;
705721 }
@@ -762,7 +778,7 @@ string useDoubleQuotes(string value)
762778
763779 executionContext . Warning ( $ "Docker container { container . ContainerId } is not in running state.") ;
764780 }
765- else if ( useAgentNode && useNode20ToStartContainer )
781+ else if ( useAgentNode && ( useNode20ToStartContainer || useNode24ToStartContainer ) )
766782 {
767783 bool containerStartupCompleted = false ;
768784 int containerStartupTimeoutInMilliseconds = 10000 ;
@@ -777,23 +793,39 @@ string useDoubleQuotes(string value)
777793
778794 foreach ( string logLine in containerLogs )
779795 {
780- if ( logLine . Contains ( labelContainerStartupUsingNode20 ) )
796+ if ( logLine . Contains ( labelContainerStartupUsingNode24 ) )
781797 {
782- executionContext . Debug ( "Using Node 20 for container startup." ) ;
798+ executionContext . Debug ( "Using Node 24 for container startup." ) ;
799+ containerStartupCompleted = true ;
800+ container . ResultNodePath = node24ContainerPath ;
801+ break ;
802+ }
803+ else if ( logLine . Contains ( labelContainerStartupUsingNode20 ) )
804+ {
805+ string warningMsg = useNode24ToStartContainer
806+ ? "Cannot run Node 24 in container. Falling back to Node 20 for container startup."
807+ : "Using Node 20 for container startup." ;
808+ executionContext . Warning ( warningMsg ) ;
783809 containerStartupCompleted = true ;
784810 container . ResultNodePath = node20ContainerPath ;
785811 break ;
786812 }
787813 else if ( logLine . Contains ( labelContainerStartupUsingNode16 ) )
788814 {
789- executionContext . Warning ( "Can not run Node 20 in container. Falling back to Node 16 for container startup." ) ;
815+ string warningMsg = useNode24ToStartContainer
816+ ? "Cannot run Node 24 and Node 20 in container. Falling back to Node 16 for container startup."
817+ : "Cannot run Node 20 in container. Falling back to Node 16 for container startup." ;
818+ executionContext . Warning ( warningMsg ) ;
790819 containerStartupCompleted = true ;
791820 container . ResultNodePath = node16ContainerPath ;
792821 break ;
793822 }
794823 else if ( logLine . Contains ( labelContainerStartupFailed ) )
795824 {
796- executionContext . Error ( "Can not run both Node 20 and Node 16 in container. Container startup failed." ) ;
825+ string errorMsg = useNode24ToStartContainer
826+ ? "Cannot run Node 24, Node 20, and Node 16 in container. Container startup failed."
827+ : "Cannot run both Node 20 and Node 16 in container. Container startup failed." ;
828+ executionContext . Error ( errorMsg ) ;
797829 containerStartupCompleted = true ;
798830 break ;
799831 }
@@ -1114,8 +1146,30 @@ string useDoubleQuotes(string value)
11141146 if ( PlatformUtil . RunningOnLinux )
11151147 {
11161148 bool useNode20InUnsupportedSystem = AgentKnobs . UseNode20InUnsupportedSystem . GetValue ( executionContext ) . AsBoolean ( ) ;
1149+ bool useNode24InUnsupportedSystem = AgentKnobs . UseNode24InUnsupportedSystem . GetValue ( executionContext ) . AsBoolean ( ) ;
1150+
1151+ if ( ! useNode24InUnsupportedSystem )
1152+ {
1153+ var node24 = container . TranslateToContainerPath ( Path . Combine ( HostContext . GetDirectory ( WellKnownDirectory . Externals ) , NodeHandler . Node24Folder , "bin" , $ "node{ IOUtil . ExeExtension } ") ) ;
1154+
1155+ string node24TestCmd = $ "bash -c \" { node24 } -v\" ";
1156+ List < string > node24VersionOutput = await DockerExec ( executionContext , container . ContainerId , node24TestCmd , noExceptionOnError : true ) ;
1157+
1158+ container . NeedsNode20Redirect = WorkerUtilities . IsCommandResultGlibcError ( executionContext , node24VersionOutput , out string node24InfoLine ) ;
11171159
1118- if ( ! useNode20InUnsupportedSystem )
1160+ if ( container . NeedsNode20Redirect )
1161+ {
1162+ PublishTelemetry (
1163+ executionContext ,
1164+ new Dictionary < string , string >
1165+ {
1166+ { "ContainerNode24to20Fallback" , container . NeedsNode20Redirect . ToString ( ) }
1167+ }
1168+ ) ;
1169+ }
1170+ }
1171+
1172+ if ( ! useNode20InUnsupportedSystem && ( useNode24InUnsupportedSystem || container . NeedsNode20Redirect ) )
11191173 {
11201174 var node20 = container . TranslateToContainerPath ( Path . Combine ( HostContext . GetDirectory ( WellKnownDirectory . Externals ) , NodeHandler . Node20_1Folder , "bin" , $ "node{ IOUtil . ExeExtension } ") ) ;
11211175
@@ -1130,12 +1184,24 @@ string useDoubleQuotes(string value)
11301184 executionContext ,
11311185 new Dictionary < string , string >
11321186 {
1133- { "ContainerNode20to16Fallback" , container . NeedsNode16Redirect . ToString ( ) }
1187+ { "ContainerNode20to16Fallback" , container . NeedsNode16Redirect . ToString ( ) }
11341188 }
11351189 ) ;
11361190 }
11371191 }
11381192
1193+ if ( ! container . NeedsNode20Redirect )
1194+ {
1195+ container . ResultNodePath = container . TranslateToContainerPath ( Path . Combine ( HostContext . GetDirectory ( WellKnownDirectory . Externals ) , NodeHandler . Node24Folder , "bin" , $ "node{ IOUtil . ExeExtension } ") ) ;
1196+ }
1197+ else if ( ! container . NeedsNode16Redirect )
1198+ {
1199+ container . ResultNodePath = container . TranslateToContainerPath ( Path . Combine ( HostContext . GetDirectory ( WellKnownDirectory . Externals ) , NodeHandler . Node20_1Folder , "bin" , $ "node{ IOUtil . ExeExtension } ") ) ;
1200+ }
1201+ else
1202+ {
1203+ container . ResultNodePath = container . TranslateToContainerPath ( Path . Combine ( HostContext . GetDirectory ( WellKnownDirectory . Externals ) , NodeHandler . Node16Folder , "bin" , $ "node{ IOUtil . ExeExtension } ") ) ;
1204+ }
11391205 }
11401206
11411207 if ( ! string . IsNullOrEmpty ( containerUserName ) )
0 commit comments