} // Calculate /// <summary> /// Open a workbook on Azure /// </summary> /// <param name="workbookPath">path specified in calculate call</param> /// <param name="lastSaveDate">last save date if specified</param> private void OpenWorkbookOnAzure(string workbookPath, DateTime?lastSaveDate) { // If on azure, get the package path string packageName = Path.GetFileNameWithoutExtension(workbookPath); string packagePath = AzureUtil.GetServiceLocalCacheFullPath(packageName); if (!string.IsNullOrEmpty(packagePath)) { // If package path was found, try to open workbook there string packageWorkbookPath = Path.Combine(packagePath, Path.GetFileName(workbookPath)); try { this.OpenWorkbook(packageWorkbookPath, lastSaveDate); } catch (FileNotFoundException) { // If unable to find workbook, retry with Tracing.WriteDebugTextWarning(Tracing.ComponentId.ExcelService, Resources.ExcelService_CantFindPackageWB, packageWorkbookPath, workbookPath); this.AzureRetryWithWorkbookPath(workbookPath, lastSaveDate, packageWorkbookPath); } } else { // Log warning about being unable to find package name Tracing.WriteDebugTextWarning(Tracing.ComponentId.ExcelService, Resources.ExcelService_CantFindPackage, packageName, workbookPath); this.AzureRetryWithWorkbookPath(workbookPath, lastSaveDate, packageName); } }
/// <summary> /// Newest experimental calculate method /// </summary> /// <param name="macroName">Macro Name</param> /// <param name="inputs">Serialized Inputs</param> /// <param name="lastSaveDate">Last save date of workbook (or null)</param> /// <returns>Serialized result from macro </returns> public byte[] Calculate(string macroName, byte[] inputs, DateTime?lastSaveDate) { try { byte[] retVal = null; // Check if driver and excel process are available and if they are, find out if the excel process has gone down. if (this.xl != null ? (this.xl.ExcelProcess != null ? this.xl.ExcelProcess.HasExited : false) : false) { // If the process has gone down, clean up the previously created ExcelDriver // and create a new one before trying to open the workbook again this.xl.Dispose(); this.xl = new ExcelDriver(); this.workbookLoaded = false; } // Check if workbook already loaded if (this.workbookLoaded == false) { // Note whether workbook was loaded Tracing.WriteDebugTextVerbose(Tracing.ComponentId.ExcelService, Resources.ExcelService_FirstRequest); // Try to get Microsoft.Hpc.Excel.WorkbookPath environment variable string FindWorkBookPath() { var path = Environment.ExpandEnvironmentVariables(Environment.GetEnvironmentVariable(this.WORKBOOKENVVAR)); if (string.IsNullOrEmpty(path)) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.HPCExcelServiceWorkbookNotSet, this.WORKBOOKENVVAR)); } if (File.Exists(path)) { return(path); } else { string dataServiceShared = Environment.GetEnvironmentVariable(this.DATASERVICESHAREDENVVAR); if (string.IsNullOrEmpty(dataServiceShared)) { throw new InvalidOperationException(string.Format($"Can't find {path}, no files are shared through data service.")); } else { var workbookName = Path.GetFileName(path); foreach (var filePath in dataServiceShared.Split(';')) { if (Path.GetFileName(filePath) == workbookName) { return(filePath); } } throw new InvalidOperationException(string.Format($"Can't find {path} in files shared through data service: {dataServiceShared}.")); } } } string workbookPath = FindWorkBookPath(); Tracing.SoaTrace(XlTraceLevel.Information, $"Find workbook in {workbookPath}"); // Perform different workbook open logic on Azure than on premise if (AzureUtil.IsOnAzure()) { this.OpenWorkbookOnAzure(workbookPath, lastSaveDate); } else { this.xl.OpenReadOnly = true; this.OpenWorkbook(workbookPath, lastSaveDate); } // Register OnExiting callback this.SetOnExitingHook(); } else { Tracing.WriteDebugTextVerbose(Tracing.ComponentId.ExcelService, Resources.ExcelService_OtherRequest); } object returnedValue = null; WorkItem workItem = null; // Deserialize inputs try { workItem = WorkItem.Deserialize(inputs); } catch (Exception ex) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.HPCExcelServiceDeserializeFailed, this.SERVICENAME), ex); } // Run the macro of provided name with inputs converted into an object returnedValue = this.xl.RunMacro(macroName, workItem.GetAll()); // Convert the returned object into work item WorkItem outputs = null; outputs = new WorkItem(); outputs.Insert(0, returnedValue); // Serialize the work item for WCF try { retVal = WorkItem.Serialize(outputs); } catch (Exception ex) { throw new SerializationException(string.Format(CultureInfo.CurrentCulture, Resources.HPCExcelServiceSerializeFailed, macroName), ex); } return(retVal); } catch (Exception ex) { // Handle corrupt workbooks as hard faults rather than retry operation exceptions. Bug 10285. bool corruptWorkbook = false; // Check for IO Exception containing COM Exception specific to corrupt workbook. if (ex.GetType().Equals(typeof(System.IO.IOException)) && ex.InnerException != null && ex.InnerException.GetType().Equals(typeof(COMException))) { COMException cex = (COMException)ex.InnerException; if ((uint)cex.ErrorCode == 0x800A03EC) { corruptWorkbook = true; } } // Failure logged and returned to client via new Exception if (this.workbookLoaded || corruptWorkbook) { // If the workbook has been loaded successfully, then the compute node is set up correctly and it is an // application error. Also report corrupt workbooks in this way to avoid retrying. Tracing.TraceEvent(XlTraceLevel.Error, Tracing.ComponentId.ExcelService, ex.ToString(), delegate { Tracing.EventProvider.LogExcelService_ApplicationError(Environment.GetEnvironmentVariable(this.SESSIONEV), Environment.GetEnvironmentVariable(this.TASKEV), Environment.GetEnvironmentVariable(this.NODENAMEEV), ex.ToString()); }); throw new FaultException <ExcelServiceError>(new ExcelServiceError(ex), Environment.GetEnvironmentVariable(this.NODENAMEEV) + ": " + ex.ToString()); } else { // If the workbook has not been loaded successfully, then the compute node is not set up correctly. // Either it cannot access the workbook, it cannot open excel, or it cannot load other installed HPC components. Tracing.TraceEvent(XlTraceLevel.Error, Tracing.ComponentId.ExcelService, ex.ToString(), delegate { Tracing.EventProvider.LogExcelService_SystemicFailure(Environment.GetEnvironmentVariable(this.SESSIONEV), Environment.GetEnvironmentVariable(this.TASKEV), Environment.GetEnvironmentVariable(this.NODENAMEEV), ex.ToString()); }); throw new FaultException <RetryOperationError>(new RetryOperationError(Environment.GetEnvironmentVariable(this.NODENAMEEV) + ": " + ex.ToString()), Environment.GetEnvironmentVariable(this.NODENAMEEV) + ": " + ex.ToString()); } } } // Calculate