Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Dynamo Service Mode as new CLI flag #13659

Merged
merged 20 commits into from
Feb 16, 2023
Merged
55 changes: 44 additions & 11 deletions src/DynamoApplications/StartupUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ public static CommandLineArguments Parse(string[] args)
bool keepAlive = false;
bool showHelp = false;
bool noConsole = false;
bool serviceMode = false;
string userDataFolder = string.Empty;
string commonDataFolder = string.Empty;

Expand Down Expand Up @@ -220,7 +221,9 @@ public static CommandLineArguments Parse(string[] args)
.Add("si=|SI=|sessionId", "Identify Dynamo host analytics session id", si => sessionId = si)
.Add("pi=|PI=|parentId", "Identify Dynamo host analytics parent id", pi => parentId = pi)
.Add("da|DA|disableAnalytics", "Disables analytics in Dynamo for the process liftime", da => disableAnalytics = da != null)
.Add("cr=|CR=|cerLocation", "Specify the crash error report tool location on disk ", cr => cerLocation = cr);
.Add("cr=|CR=|cerLocation", "Specify the crash error report tool location on disk ", cr => cerLocation = cr)
.Add("s|S|service mode", "Service mode, bypass certain Dynamo launch steps for maximum startup performance", s => serviceMode = s != null);
QilongTang marked this conversation as resolved.
Show resolved Hide resolved

optionsSet.Parse(args);

if (showHelp)
Expand Down Expand Up @@ -249,7 +252,8 @@ public static CommandLineArguments Parse(string[] args)
CommonDataFolder = commonDataFolder,
DisableAnalytics = disableAnalytics,
AnalyticsInfo = new HostAnalyticsInfo() { HostName = hostname, ParentId = parentId, SessionId = sessionId },
CERLocation = cerLocation
CERLocation = cerLocation,
ServiceMode = serviceMode
};
#endif
}
Expand Down Expand Up @@ -279,6 +283,11 @@ private static void ShowHelp(OptionSet opSet)
public bool DisableAnalytics { get; set; }
public HostAnalyticsInfo AnalyticsInfo { get; set; }
public string CERLocation { get; set; }

/// <summary>
/// Boolean indication of launching Dynamo in service mode, this mode it optimized for minimal launch time
QilongTang marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public bool ServiceMode { get; set; }
}

/// <summary>
Expand Down Expand Up @@ -327,7 +336,8 @@ private static IUpdateManager InitializeUpdateManager()
/// </summary>
/// <param name="asmPath">Path to directory containing geometry library binaries</param>
/// <param name="userDataFolder">Path to be used by PathResolver for UserDataFolder</param>
/// <param name="commonDataFolder">Path to be used by PathResolver for CommonDataFolder</param>
/// <param name="commonDataFolder">Path to be used by PathResolver for CommonDataFolder</param>
/// <param name="info">Host analytics info specifying Dynamo launching host related information.</param>
/// <returns></returns>
public static DynamoModel MakeCLIModel(string asmPath, string userDataFolder, string commonDataFolder, HostAnalyticsInfo info = new HostAnalyticsInfo())
{
Expand All @@ -339,6 +349,25 @@ private static IUpdateManager InitializeUpdateManager()
return model;
}

/// <summary>
/// Use this overload to construct a DynamoModel in CLI context when the location of ASM to use is known, host analytics info is known and you want to set data paths.
/// </summary>
/// <param name="asmPath">Path to directory containing geometry library binaries</param>
/// <param name="userDataFolder">Path to be used by PathResolver for UserDataFolder</param>
/// <param name="commonDataFolder">Path to be used by PathResolver for CommonDataFolder</param>
/// <param name="info">Host analytics info specifying Dynamo launching host related information.</param>
/// <param name="isServiceMode">Boolean indication of launching Dynamo in service mode, this mode it optimized for minimal launch time.</param>
/// <returns></returns>
public static DynamoModel MakeCLIModel(string asmPath, string userDataFolder, string commonDataFolder, HostAnalyticsInfo info = new HostAnalyticsInfo(), bool isServiceMode = false)
Copy link
Contributor

Choose a reason for hiding this comment

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

I have also added a couple of flags last year :). I guess we need to think of something soon to better consolidate all the MakeModel constructs. Perhaps a startup config file where you can enable/disable features/extensions etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed, currently the code (constructors) used for CLI are a bit messy

{
// Preload ASM and display corresponding message on splash screen
DynamoModel.OnRequestUpdateLoadBarStatus(new SplashScreenLoadEventArgs(Resources.SplashScreenPreLoadingAsm, 10));
var isASMloaded = PreloadASM(asmPath, out string geometryFactoryPath, out string preloaderLocation);
var model = StartDynamoWithDefaultConfig(true, userDataFolder, commonDataFolder, geometryFactoryPath, preloaderLocation, info, isServiceMode);
model.IsASMLoaded = isASMloaded;
return model;
}

/// <summary>
/// Use this overload to construct a DynamoModel when the location of ASM to use is known and host name is known.
/// </summary>
Expand All @@ -359,7 +388,7 @@ public static DynamoModel MakeModel(bool CLImode, string asmPath = "", string ho
/// </summary>
/// <param name="CLImode">CLI mode starts the model in test mode and uses a separate path resolver.</param>
/// <param name="asmPath">Path to directory containing geometry library binaries</param>
/// <param name="info">Host analytics info</param>
/// <param name="info">Host analytics info specifying Dynamo launching host related information.</param>
/// <returns></returns>
public static DynamoModel MakeModel(bool CLImode, string asmPath = "", HostAnalyticsInfo info = new HostAnalyticsInfo())
{
Expand Down Expand Up @@ -455,19 +484,23 @@ private static DynamoModel StartDynamoWithDefaultConfig(bool CLImode,
string commonDataFolder,
string geometryFactoryPath,
string preloaderLocation,
HostAnalyticsInfo info = new HostAnalyticsInfo())
HostAnalyticsInfo info = new HostAnalyticsInfo(),
bool isServiceMode = false)
{
var config = new DynamoModel.DefaultStartConfiguration()
var config = new DynamoModel.DefaultStartConfiguration
{
GeometryFactoryPath = geometryFactoryPath,
ProcessMode = CLImode ? TaskProcessMode.Synchronous : TaskProcessMode.Asynchronous,
HostAnalyticsInfo = info,
CLIMode = CLImode
CLIMode = CLImode,
AuthProvider = CLImode ? null : new Core.IDSDKManager(),
UpdateManager = CLImode ? null : OSHelper.IsWindows() ? InitializeUpdateManager() : null,
StartInTestMode = CLImode,
PathResolver = CLImode ? new CLIPathResolver(preloaderLocation, userDataFolder, commonDataFolder) as IPathResolver : new SandboxPathResolver(preloaderLocation) as IPathResolver,
// TODO: Dynamo 3.0
// Update Default start config to include IsServiceMode so DynamoModel can be initialize with that flag. For now, reuse the legacy Context property
QilongTang marked this conversation as resolved.
Show resolved Hide resolved
Context = isServiceMode ? "Service": string.Empty
};
config.AuthProvider = CLImode ? null : new Core.IDSDKManager();
config.UpdateManager = CLImode ? null : OSHelper.IsWindows() ? InitializeUpdateManager() : null;
config.StartInTestMode = CLImode;
config.PathResolver = CLImode ? new CLIPathResolver(preloaderLocation, userDataFolder, commonDataFolder) as IPathResolver : new SandboxPathResolver(preloaderLocation) as IPathResolver;

var model = DynamoModel.Start(config);
return model;
Expand Down
12 changes: 6 additions & 6 deletions src/DynamoCLI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using Dynamo.Applications;
using Dynamo.Models;
Expand Down Expand Up @@ -29,9 +27,10 @@ static internal void Main(string[] args)

if (cmdLineArgs.KeepAlive)
{
var thread = new Thread(() => RunKeepAlive(cmdLineArgs));

thread.Name = "DynamoModelKeepAlive";
var thread = new Thread(() => RunKeepAlive(cmdLineArgs))
{
Name = "DynamoModelKeepAlive"
};
thread.Start();

if (!useConsole)
Expand Down Expand Up @@ -104,7 +103,8 @@ private static DynamoModel StartupDynamo(StartupUtils.CommandLineArguments cmdLi
model = Dynamo.Applications.StartupUtils.MakeCLIModel(String.IsNullOrEmpty(cmdLineArgs.ASMPath) ? string.Empty : cmdLineArgs.ASMPath,
cmdLineArgs.UserDataFolder,
cmdLineArgs.CommonDataFolder,
cmdLineArgs.AnalyticsInfo);
cmdLineArgs.AnalyticsInfo,
cmdLineArgs.ServiceMode);

if (!string.IsNullOrEmpty(cmdLineArgs.CERLocation))
{
Expand Down
8 changes: 0 additions & 8 deletions src/DynamoCore/Core/AuthenticationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,6 @@ internal void ToggleLoginState(object o)
}
}

/// <summary>
/// Check if able to toggle login state
/// </summary>
internal bool CanToggleLoginState()
{
return this.LoginState == LoginState.LoggedOut || this.LoginState == LoginState.LoggedIn;
}

internal void Login()
{
if (!HasAuthProvider) return;
Expand Down
4 changes: 2 additions & 2 deletions src/DynamoCore/Extensions/StartupParams.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using Dynamo.Graph.Nodes.CustomNodes;
using Dynamo.Interfaces;
using Dynamo.Library;
Expand Down Expand Up @@ -111,7 +111,7 @@ public StartupParams(IAuthProvider provider, IPathManager pathManager,
/// </summary>
internal StartupParams(DynamoModel dynamoModel)
{
this.authProvider = dynamoModel.AuthenticationManager.AuthProvider;
this.authProvider = dynamoModel.AuthenticationManager?.AuthProvider;
this.pathManager = dynamoModel.PathManager;
this.libraryLoader = new ExtensionLibraryLoader(dynamoModel);
this.customNodeManager = dynamoModel.CustomNodeManager;
Expand Down
89 changes: 56 additions & 33 deletions src/DynamoCore/Models/DynamoModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ public string Version
/// </summary>
public HostAnalyticsInfo HostAnalyticsInfo { get; set; }

/// <summary>
/// Boolean indication of launching Dynamo in service mode, this mode it optimized for minimal launch time, mostly leveraged by CLI or WPF CLI.
QilongTang marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public bool IsServiceMode { get; set; }
QilongTang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// UpdateManager to handle automatic upgrade to higher version.
/// </summary>
Expand Down Expand Up @@ -637,15 +642,21 @@ protected DynamoModel(IStartConfiguration config)
pathManager.EnsureDirectoryExistence(exceptions);

Context = config.Context;
// This condition could be updated later depending on if we reuse the legacy Context property
IsServiceMode = config.Context.Equals("Service");
IsTestMode = config.StartInTestMode;
IsHeadless = config.IsHeadless;

DebugSettings = new DebugSettings();
Logger = new DynamoLogger(DebugSettings, pathManager.LogDirectory, IsTestMode, CLIMode);

foreach (var exception in exceptions)
if (!IsServiceMode)
{
Logger.Log(exception); // Log all exceptions.
// Log all exceptions as part of directories check.
foreach (var exception in exceptions)
{
Logger.Log(exception);
}
}

MigrationManager = new MigrationManager(DisplayFutureFileMessage, DisplayObsoleteFileMessage);
Expand Down Expand Up @@ -682,26 +693,29 @@ protected DynamoModel(IStartConfiguration config)
}

bool areAnalyticsDisabledFromConfig = false;
try
{
// Dynamo, behind a proxy server, has been known to have issues loading the Analytics binaries.
// Using the "DisableAnalytics" configuration setting, a user can skip loading analytics binaries altogether.
var assemblyConfig = ConfigurationManager.OpenExeConfiguration(GetType().Assembly.Location);
if (assemblyConfig != null)
if (!IsServiceMode)
{ // Skip getting the value for areAnalyticsDisabledFromConfig because analytics is disabled for searvice mode anyway
try
{
var disableAnalyticsValue = assemblyConfig.AppSettings.Settings["DisableAnalytics"];
if (disableAnalyticsValue != null)
bool.TryParse(disableAnalyticsValue.Value, out areAnalyticsDisabledFromConfig);
// Dynamo, behind a proxy server, has been known to have issues loading the Analytics binaries.
// Using the "DisableAnalytics" configuration setting, a user can skip loading analytics binaries altogether.
var assemblyConfig = ConfigurationManager.OpenExeConfiguration(GetType().Assembly.Location);
if (assemblyConfig != null)
{
var disableAnalyticsValue = assemblyConfig.AppSettings.Settings["DisableAnalytics"];
if (disableAnalyticsValue != null)
bool.TryParse(disableAnalyticsValue.Value, out areAnalyticsDisabledFromConfig);
}
}
catch (Exception)
{
// Do nothing for now
}
}
catch (Exception)
{
// Do nothing for now
}

// If user skipped analytics from assembly config, do not try to launch the analytics client
// or the feature flags client.
if (!areAnalyticsDisabledFromConfig && !Dynamo.Logging.Analytics.DisableAnalytics)
// or the feature flags client for web traffic reason.
if (!areAnalyticsDisabledFromConfig && !Dynamo.Logging.Analytics.DisableAnalytics && !IsServiceMode)
QilongTang marked this conversation as resolved.
Show resolved Hide resolved
{
// Start the Analytics service only when a session is not present.
// In an integrator host, as splash screen can be closed without shutting down the ViewModel, the analytics service is not stopped.
Expand Down Expand Up @@ -746,7 +760,8 @@ protected DynamoModel(IStartConfiguration config)

}

if (!IsTestMode && PreferenceSettings.IsFirstRun)
// TBD: Do we need settings migrator for service mode? If we config the docker correctly, this could be skipped I think
if (!IsTestMode && PreferenceSettings.IsFirstRun && !IsServiceMode)
{
DynamoMigratorBase migrator = null;

Expand All @@ -773,7 +788,7 @@ protected DynamoModel(IStartConfiguration config)
}
}

if (PreferenceSettings.IsFirstRun && !IsTestMode)
if (PreferenceSettings.IsFirstRun && !IsTestMode && !IsServiceMode)
{
PreferenceSettings.AddDefaultTrustedLocations();
}
Expand Down Expand Up @@ -808,7 +823,7 @@ protected DynamoModel(IStartConfiguration config)
// 4) Set from OOTB hard-coded default template

// If a custom python template path doesn't already exists in the DynamoSettings.xml
if (string.IsNullOrEmpty(PreferenceSettings.PythonTemplateFilePath) || !File.Exists(PreferenceSettings.PythonTemplateFilePath))
if (string.IsNullOrEmpty(PreferenceSettings.PythonTemplateFilePath) || !File.Exists(PreferenceSettings.PythonTemplateFilePath) && !IsServiceMode)
{
// To supply a custom python template host integrators should supply a 'DefaultStartConfiguration' config file
// or create a new struct that inherits from 'DefaultStartConfiguration' making sure to set the 'PythonTemplatePath'
Expand Down Expand Up @@ -848,9 +863,12 @@ protected DynamoModel(IStartConfiguration config)
pathManager.Preferences = PreferenceSettings;
PreferenceSettings.RequestUserDataFolder += pathManager.GetUserDataFolder;

SearchModel = new NodeSearchModel(Logger);
SearchModel.ItemProduced +=
node => ExecuteCommand(new CreateNodeCommand(node, 0, 0, true, true));
if (!IsServiceMode)
{
SearchModel = new NodeSearchModel(Logger);
SearchModel.ItemProduced +=
node => ExecuteCommand(new CreateNodeCommand(node, 0, 0, true, true));
}

NodeFactory = new NodeFactory();
NodeFactory.MessageLogged += LogMessage;
Expand All @@ -860,7 +878,10 @@ protected DynamoModel(IStartConfiguration config)
extensionManager.MessageLogged += LogMessage;
var extensions = config.Extensions ?? LoadExtensions();

LinterManager = new LinterManager(this.ExtensionManager);
if (!IsServiceMode)
{
LinterManager = new LinterManager(this.ExtensionManager);
}

// when dynamo is ready, alert the loaded extensions
DynamoReady += (readyParams) =>
Expand Down Expand Up @@ -904,10 +925,13 @@ protected DynamoModel(IStartConfiguration config)

AddHomeWorkspace();

AuthenticationManager = new AuthenticationManager(config.AuthProvider);
if (!IsServiceMode)
{
AuthenticationManager = new AuthenticationManager(config.AuthProvider);
}

UpdateManager.Log += UpdateManager_Log;
if (!IsTestMode && !IsHeadless)
if (!IsTestMode && !IsHeadless && !IsServiceMode)
{
DefaultUpdateManager.CheckForProductUpdate(UpdateManager);
}
Expand All @@ -924,8 +948,7 @@ protected DynamoModel(IStartConfiguration config)

foreach (var ext in extensions)
{
var logSource = ext as ILogSource;
if (logSource != null)
if (ext is ILogSource logSource)
logSource.MessageLogged += LogMessage;

try
Expand Down Expand Up @@ -1437,7 +1460,7 @@ private void InitializeIncludedNodes()
NodeFactory.AddTypeFactoryAndLoader(outputData.Type);
NodeFactory.AddAlsoKnownAs(outputData.Type, outputData.AlsoKnownAs);

SearchModel.Add(new CodeBlockNodeSearchElement(cbnData, LibraryServices));
SearchModel?.Add(new CodeBlockNodeSearchElement(cbnData, LibraryServices));

var symbolSearchElement = new NodeModelSearchElement(symbolData)
{
Expand All @@ -1455,8 +1478,8 @@ private void InitializeIncludedNodes()
outputSearchElement.IsVisibleInSearch = isVisible;
};

SearchModel.Add(symbolSearchElement);
SearchModel.Add(outputSearchElement);
SearchModel?.Add(symbolSearchElement);
SearchModel?.Add(outputSearchElement);
}

internal static bool IsDisabledPath(string packagesDirectory, IPreferences preferences)
Expand Down Expand Up @@ -3108,7 +3131,7 @@ private void AddNodeTypeToSearch(TypeLoadData typeLoadData)
return;
}

SearchModel.Add(new NodeModelSearchElement(typeLoadData));
SearchModel?.Add(new NodeModelSearchElement(typeLoadData));
}

/// <summary>
Expand Down Expand Up @@ -3155,7 +3178,7 @@ private void AddZeroTouchNodeToSearch(FunctionDescriptor functionDescriptor)
{
if (functionDescriptor.IsVisibleInLibrary)
{
SearchModel.Add(new ZeroTouchSearchElement(functionDescriptor));
SearchModel?.Add(new ZeroTouchSearchElement(functionDescriptor));
}
}

Expand Down
Loading