optimize the System Update process
This commit is contained in:
		@ -15,17 +15,19 @@ namespace Oqtane.Updater
 | 
			
		||||
        /// <param name="args"></param>
 | 
			
		||||
        static void Main(string[] args)
 | 
			
		||||
        {
 | 
			
		||||
            // requires 2 arguments - the ContentRootPath and the WebRootPath of the site
 | 
			
		||||
            // requires 3 arguments - the ContentRootPath, the WebRootPath of the site, and a backup flag
 | 
			
		||||
 | 
			
		||||
            // for testing purposes you can uncomment and modify the logic below
 | 
			
		||||
            //Array.Resize(ref args, 2);
 | 
			
		||||
            //Array.Resize(ref args, 3);
 | 
			
		||||
            //args[0] = @"C:\yourpath\oqtane.framework\Oqtane.Server";
 | 
			
		||||
            //args[1] = @"C:\yourpath\oqtane.framework\Oqtane.Server\wwwroot";
 | 
			
		||||
            //args[2] = @"true";
 | 
			
		||||
 | 
			
		||||
            if (args.Length == 2)
 | 
			
		||||
            if (args.Length == 3)
 | 
			
		||||
            {
 | 
			
		||||
                string contentrootfolder = args[0];
 | 
			
		||||
                string webrootfolder = args[1];
 | 
			
		||||
                bool backup = bool.Parse(args[2]);
 | 
			
		||||
 | 
			
		||||
                string deployfolder = Path.Combine(contentrootfolder, "Packages");
 | 
			
		||||
                string backupfolder = Path.Combine(contentrootfolder, "Backup");
 | 
			
		||||
@ -49,6 +51,7 @@ namespace Oqtane.Updater
 | 
			
		||||
                    WriteLog(logFilePath, "Upgrade Process Started: " + DateTime.UtcNow.ToString() + Environment.NewLine);
 | 
			
		||||
                    WriteLog(logFilePath, "ContentRootPath: " + contentrootfolder + Environment.NewLine);
 | 
			
		||||
                    WriteLog(logFilePath, "WebRootPath: " + webrootfolder + Environment.NewLine);
 | 
			
		||||
 | 
			
		||||
                    if (packagename != "" && File.Exists(Path.Combine(webrootfolder, "app_offline.bak")))
 | 
			
		||||
                    {
 | 
			
		||||
                        WriteLog(logFilePath, "Located Upgrade Package: " + packagename + Environment.NewLine);
 | 
			
		||||
@ -74,12 +77,12 @@ namespace Oqtane.Updater
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        bool success = true;
 | 
			
		||||
                        // ensure files are not locked
 | 
			
		||||
                        if (CanAccessFiles(files))
 | 
			
		||||
 | 
			
		||||
                        if (backup)
 | 
			
		||||
                        {
 | 
			
		||||
                            UpdateOfflineContent(offlineFilePath, offlineTemplate, 10, "Preparing Backup Folder");
 | 
			
		||||
                            WriteLog(logFilePath, "Preparing Backup Folder: " + backupfolder + Environment.NewLine);
 | 
			
		||||
                            
 | 
			
		||||
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                // clear out backup folder
 | 
			
		||||
@ -112,8 +115,28 @@ namespace Oqtane.Updater
 | 
			
		||||
                                            {
 | 
			
		||||
                                                Directory.CreateDirectory(Path.GetDirectoryName(filename));
 | 
			
		||||
                                            }
 | 
			
		||||
                                            File.Copy(file, filename);
 | 
			
		||||
                                            WriteLog(logFilePath, "Copy File: " + filename + Environment.NewLine);
 | 
			
		||||
 | 
			
		||||
                                            try
 | 
			
		||||
                                            {
 | 
			
		||||
                                                // try optimistically to backup the file
 | 
			
		||||
                                                File.Copy(file, filename);
 | 
			
		||||
                                                WriteLog(logFilePath, "Copy File: " + filename + Environment.NewLine);
 | 
			
		||||
                                            }
 | 
			
		||||
                                            catch
 | 
			
		||||
                                            {
 | 
			
		||||
                                                // if the file is locked, wait until it is unlocked
 | 
			
		||||
                                                if (CanAccessFile(file))
 | 
			
		||||
                                                {
 | 
			
		||||
                                                    File.Copy(file, filename);
 | 
			
		||||
                                                    WriteLog(logFilePath, "Copy File: " + filename + Environment.NewLine);
 | 
			
		||||
                                                }
 | 
			
		||||
                                                else
 | 
			
		||||
                                                {
 | 
			
		||||
                                                    // file could not be backed up, upgrade unsuccessful
 | 
			
		||||
                                                    success = false;
 | 
			
		||||
                                                    WriteLog(logFilePath, "Error Backing Up Files" + Environment.NewLine);
 | 
			
		||||
                                                }
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                    catch (Exception ex)
 | 
			
		||||
@ -125,17 +148,20 @@ namespace Oqtane.Updater
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                            // extract files
 | 
			
		||||
                            if (success)
 | 
			
		||||
                        // extract files
 | 
			
		||||
                        if (success)
 | 
			
		||||
                        {
 | 
			
		||||
                            UpdateOfflineContent(offlineFilePath, offlineTemplate, 50, "Extracting Files From Upgrade Package");
 | 
			
		||||
                            WriteLog(logFilePath, "Extracting Files From Upgrade Package..." + Environment.NewLine);
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                UpdateOfflineContent(offlineFilePath, offlineTemplate, 50, "Extracting Files From Upgrade Package");
 | 
			
		||||
                                WriteLog(logFilePath, "Extracting Files From Upgrade Package..." + Environment.NewLine);
 | 
			
		||||
                                try
 | 
			
		||||
                                using (ZipArchive archive = ZipFile.OpenRead(packagename))
 | 
			
		||||
                                {
 | 
			
		||||
                                    using (ZipArchive archive = ZipFile.OpenRead(packagename))
 | 
			
		||||
                                    foreach (ZipArchiveEntry entry in archive.Entries)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        foreach (ZipArchiveEntry entry in archive.Entries)
 | 
			
		||||
                                        if (success)
 | 
			
		||||
                                        {
 | 
			
		||||
                                            if (!string.IsNullOrEmpty(entry.Name))
 | 
			
		||||
                                            {
 | 
			
		||||
@ -144,20 +170,42 @@ namespace Oqtane.Updater
 | 
			
		||||
                                                {
 | 
			
		||||
                                                    Directory.CreateDirectory(Path.GetDirectoryName(filename));
 | 
			
		||||
                                                }
 | 
			
		||||
                                                entry.ExtractToFile(filename, true);
 | 
			
		||||
                                                WriteLog(logFilePath, "Exact File: " + filename + Environment.NewLine);
 | 
			
		||||
 | 
			
		||||
                                                try
 | 
			
		||||
                                                {
 | 
			
		||||
                                                    // try optimistically to extract the file
 | 
			
		||||
                                                    entry.ExtractToFile(filename, true);
 | 
			
		||||
                                                    WriteLog(logFilePath, "Exact File: " + filename + Environment.NewLine);
 | 
			
		||||
                                                }
 | 
			
		||||
                                                catch
 | 
			
		||||
                                                {
 | 
			
		||||
                                                    // if the file is locked, wait until it is unlocked
 | 
			
		||||
                                                    if (CanAccessFile(filename))
 | 
			
		||||
                                                    {
 | 
			
		||||
                                                        entry.ExtractToFile(filename, true);
 | 
			
		||||
                                                        WriteLog(logFilePath, "Exact File: " + filename + Environment.NewLine);
 | 
			
		||||
                                                    }
 | 
			
		||||
                                                    else
 | 
			
		||||
                                                    {
 | 
			
		||||
                                                        // file could not be extracted, upgrade unsuccessful
 | 
			
		||||
                                                        success = false;
 | 
			
		||||
                                                        WriteLog(logFilePath, "Error Extracting Files From Upgrade Package" + Environment.NewLine);
 | 
			
		||||
                                                    }
 | 
			
		||||
                                                }
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                catch (Exception ex)
 | 
			
		||||
                                {
 | 
			
		||||
                                    success = false;
 | 
			
		||||
                                    UpdateOfflineContent(offlineFilePath, offlineTemplate, 95, "Error Extracting Files From Upgrade Package", "bg-danger");
 | 
			
		||||
                                    WriteLog(logFilePath, "Error Extracting Files From Upgrade Package: " + ex.Message + Environment.NewLine);
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (Exception ex)
 | 
			
		||||
                            {
 | 
			
		||||
                                success = false;
 | 
			
		||||
                                WriteLog(logFilePath, "Error Extracting Files From Upgrade Package: " + ex.Message + Environment.NewLine);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                                if (success)
 | 
			
		||||
                            if (success)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (backup)
 | 
			
		||||
                                {
 | 
			
		||||
                                    UpdateOfflineContent(offlineFilePath, offlineTemplate, 90, "Removing Backup Folder");
 | 
			
		||||
                                    WriteLog(logFilePath, "Removing Backup Folder..." + Environment.NewLine);
 | 
			
		||||
@ -174,7 +222,12 @@ namespace Oqtane.Updater
 | 
			
		||||
                                        WriteLog(logFilePath, "Error Removing Backup Folder: " + ex.Message + Environment.NewLine);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                else
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                UpdateOfflineContent(offlineFilePath, offlineTemplate, 95, "Error Extracting Files From Upgrade Package", "bg-danger");
 | 
			
		||||
 | 
			
		||||
                                if (backup)
 | 
			
		||||
                                {
 | 
			
		||||
                                    UpdateOfflineContent(offlineFilePath, offlineTemplate, 50, "Upgrade Failed, Restoring Files From Backup Folder", "bg-warning");
 | 
			
		||||
                                    WriteLog(logFilePath, "Restoring Files From Backup Folder..." + Environment.NewLine);
 | 
			
		||||
@ -201,18 +254,14 @@ namespace Oqtane.Updater
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                UpdateOfflineContent(offlineFilePath, offlineTemplate, 95, "Upgrade Failed: Could Not Backup Files", "bg-danger");
 | 
			
		||||
                                WriteLog(logFilePath, "Upgrade Failed: Could Not Backup Files" + Environment.NewLine);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            UpdateOfflineContent(offlineFilePath, offlineTemplate, 95, "Upgrade Failed: Some Files Are Locked By The Hosting Environment", "bg-danger");
 | 
			
		||||
                            WriteLog(logFilePath, "Upgrade Failed: Some Files Are Locked By The Hosting Environment" + Environment.NewLine);
 | 
			
		||||
                            UpdateOfflineContent(offlineFilePath, offlineTemplate, 95, "Upgrade Failed: Could Not Backup Files", "bg-danger");
 | 
			
		||||
                            WriteLog(logFilePath, "Upgrade Failed: Could Not Backup Files" + Environment.NewLine);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                        UpdateOfflineContent(offlineFilePath, offlineTemplate, 100, "Upgrade Process Finished, Reloading", success ? "" : "bg-danger");
 | 
			
		||||
                        Thread.Sleep(3000); //wait for 3 seconds to complete the upgrade process.
 | 
			
		||||
                        // bring the app back online
 | 
			
		||||
@ -240,55 +289,45 @@ namespace Oqtane.Updater
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool CanAccessFiles(List<string> files)
 | 
			
		||||
        private static bool CanAccessFile(string filepath)
 | 
			
		||||
        {
 | 
			
		||||
            // ensure files are not locked by another process
 | 
			
		||||
            // the IIS ShutdownTimeLimit defines the duration for app shutdown (default is 90 seconds)
 | 
			
		||||
            // websockets can delay application shutdown (ie. Blazor Server)
 | 
			
		||||
            // ensure file is not locked by another process
 | 
			
		||||
            int retries = 60;
 | 
			
		||||
            int sleep = 2;
 | 
			
		||||
 | 
			
		||||
            bool canAccess = true;
 | 
			
		||||
            int attempts = 0;
 | 
			
		||||
            FileStream stream = null;
 | 
			
		||||
            int i = 0;
 | 
			
		||||
            while (i < (files.Count - 1) && canAccess)
 | 
			
		||||
            {
 | 
			
		||||
                string filepath = files[i];
 | 
			
		||||
                int attempts = 0;
 | 
			
		||||
                bool locked = true;
 | 
			
		||||
 | 
			
		||||
                while (attempts < retries && locked)
 | 
			
		||||
            bool locked = true;
 | 
			
		||||
            while (attempts < retries && locked)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    if (File.Exists(filepath))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (File.Exists(filepath))
 | 
			
		||||
                        {
 | 
			
		||||
                            stream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.None);
 | 
			
		||||
                            locked = false;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            locked = false;
 | 
			
		||||
                        }
 | 
			
		||||
                        stream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.None);
 | 
			
		||||
                        locked = false;
 | 
			
		||||
                    }
 | 
			
		||||
                    catch // file is locked by another process
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        Thread.Sleep(sleep * 1000); // wait
 | 
			
		||||
                        locked = false;
 | 
			
		||||
                    }
 | 
			
		||||
                    finally
 | 
			
		||||
                    {
 | 
			
		||||
                        stream?.Close();
 | 
			
		||||
                    }
 | 
			
		||||
                    attempts += 1;
 | 
			
		||||
                }
 | 
			
		||||
                if (locked)
 | 
			
		||||
                catch // file is locked by another process
 | 
			
		||||
                {
 | 
			
		||||
                    canAccess = false;
 | 
			
		||||
                    Console.WriteLine("File Locked: " + filepath);
 | 
			
		||||
                    Thread.Sleep(sleep * 1000); // wait
 | 
			
		||||
                }
 | 
			
		||||
                i += 1;
 | 
			
		||||
                finally
 | 
			
		||||
                {
 | 
			
		||||
                    stream?.Close();
 | 
			
		||||
                }
 | 
			
		||||
                attempts += 1;
 | 
			
		||||
            }
 | 
			
		||||
            return canAccess;
 | 
			
		||||
            if (locked)
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine("File Locked: " + filepath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return !locked;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void UpdateOfflineContent(string filePath, string contentTemplate, int progress, string status,  string progressClass =  "")
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user