/// <summary> /// Initiates a retry for specified event type. /// </summary> /// <param name="ex">Exception causing retry.</param> /// <param name="eventType">Event type to retry.</param> private void RetrySynchronizedEvent(Exception ex, int eventType) { if (m_disposed) { return; } // A retry is only being initiating for basic file I/O or locking errors - monitor these failures occurring // in quick succession so that retry activity is not allowed to go on forever... if (DateTime.UtcNow.Ticks - m_lastRetryTime > (long)Ticks.FromMilliseconds(m_retryTimer.Interval * m_maximumRetryAttempts)) { // Significant time has passed since last retry, so we reset counter m_retryCount = 0; m_lastRetryTime = DateTime.UtcNow.Ticks; } else { m_retryCount++; if (m_retryCount >= m_maximumRetryAttempts) { throw new UnauthorizedAccessException("Failed to " + (eventType == WriteEvent ? "write data to " : "read data from ") + m_fileName + " after " + m_maximumRetryAttempts + " attempts: " + ex.Message, ex); } } // Technically the inter-process mutex will handle serialized access to the file, but if the OS or other process // not participating with the mutex has the file locked, all we can do is queue up a retry for this event. lock (m_retryQueue) { m_retryQueue[eventType] = true; } m_retryTimer.Start(); }
void SetFlushTimer() { if (flushTimer == null) { int flushSkew = Ticks.ToMilliseconds(Math.Min(flushTimeout / 10, Ticks.FromMilliseconds(maxFlushSkew))); flushTimer = new IOThreadTimer(new Action <object>(OnFlushTimer), null, true, flushSkew); } flushTimer.Set(Ticks.ToTimeSpan(flushTimeout)); }
private void Initialize() { RetrieveSettingsFromIsolatedStorage(false); m_timeStampList = new ConcurrentQueue <string>(); m_yAxisDataCollection = new ConcurrentDictionary <Guid, ConcurrentQueue <double> >(); m_yAxisBindingCollection = new ConcurrentDictionary <Guid, EnumerableDataSource <double> >(); m_lineGraphCollection = new ConcurrentDictionary <Guid, LineGraph>(); m_selectedMeasurements = new ConcurrentDictionary <Guid, RealTimeMeasurement>(); m_displayedMeasurement = new ObservableCollection <RealTimeMeasurement>(); m_displayedMeasurement.CollectionChanged += m_displayedMeasurement_CollectionChanged; m_restartConnectionCycle = true; m_xAxisDataCollection = new int[m_numberOfDataPointsToPlot]; m_refreshRate = Ticks.FromMilliseconds(m_chartRefreshInterval); TextBlockMeasurementRefreshInterval.Text = m_measurementsDataRefreshInterval.ToString(); TextBlockStatisticsRefreshInterval.Text = m_statisticsDataRefershInterval.ToString(); TextBoxProcessInterval.Text = "33"; }
private void PrepareConnect(Uri remoteUri, TimeSpan timeout, out string resolvedAddress, out BackoffTimeoutHelper backoffHelper) { TimeSpan span; PipeUri.Validate(remoteUri); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, 0x4002a, System.ServiceModel.SR.GetString("TraceCodeInitiatingNamedPipeConnection"), new StringTraceRecord("Uri", remoteUri.ToString()), this, null); } resolvedAddress = GetPipeName(remoteUri); if (timeout >= TimeSpan.FromMilliseconds(300.0)) { span = TimeoutHelper.Add(timeout, TimeSpan.Zero - TimeSpan.FromMilliseconds(150.0)); } else { span = Ticks.ToTimeSpan((Ticks.FromMilliseconds(150) / 2L) + 1L); } backoffHelper = new BackoffTimeoutHelper(span, TimeSpan.FromMinutes(5.0)); }
/// <summary>Event handler for service started operation.</summary> /// <param name="sender">Event source.</param> /// <param name="e">Event arguments.</param> /// <remarks> /// Time-series framework uses this handler to handle initialization of system objects. /// </remarks> protected override void ServiceStartedHandler(object sender, EventArgs e) { base.ServiceStartedHandler(sender, e); CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"]; if (systemSettings["eDNAGrafanaControllerEnabled", true]?.Value.ParseBoolean() ?? true) { ServiceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("eDNARefreshMetadata", "Refreshes eDNA metadata.", RefreshMetaDataHandler, new[] { "eDNARefresh", "RefresheDNAMetadata" })); } if (!Model.Global.GrafanaServerInstalled) { return; } // Kick off a thread to monitor for when Grafana server has been properly // initialized so that initial user synchronization process can proceed new Thread(() => { try { const int DefaultInitializationTimeout = GrafanaAuthProxyController.DefaultInitializationTimeout; // Access settings from "systemSettings" category in configuration file CategorizedSettingsElementCollection grafanaHosting = ConfigurationFile.Current.Settings["grafanaHosting"]; // Make sure needed settings exist grafanaHosting.Add("InitializationTimeout", DefaultInitializationTimeout, "Defines the timeout, in seconds, for the Grafana system to initialize."); // Get settings as currently defined in configuration file int initializationTimeout = grafanaHosting["InitializationTimeout"].ValueAs(DefaultInitializationTimeout); DateTime startTime = DateTime.UtcNow; bool timeout = false; #if DEBUG // Debugging adds run-time overhead, provide more time for initialization initializationTimeout *= 3; int attempts = 0; #endif // Give initialization - which includes starting Grafana server process - a chance to start while (!GrafanaAuthProxyController.ServerIsResponding()) { // Stop attempts after timeout has expired if ((DateTime.UtcNow - startTime).TotalSeconds >= initializationTimeout) { timeout = true; break; } Thread.Sleep(500); #if DEBUG if (++attempts % 4 == 0) { DisplayStatusMessage($"DEBUG: Awaiting Grafana initialization, {attempts:N0} attempts so far...", UpdateType.Warning); } #endif } if (timeout) { DisplayStatusMessage($"WARNING: Service started handler reported timeout awaiting Grafana initialization. Timeout configured as {Ticks.FromMilliseconds(initializationTimeout).ToElapsedTimeString(2)}.", UpdateType.Warning); } } catch (Exception ex) { LogException(new InvalidOperationException($"Failed while checking for Grafana server initialization: {ex.Message}", ex)); } finally { GrafanaAuthProxyController.InitializationComplete(); } }) { IsBackground = true } .Start(); }
private void SetFlushTimer() { if (this.flushTimer == null) { int maxSkewInMilliseconds = Ticks.ToMilliseconds(Math.Min(this.flushTimeout / 10L, Ticks.FromMilliseconds(100))); this.flushTimer = new IOThreadTimer(new Action <object>(this.OnFlushTimer), null, true, maxSkewInMilliseconds); } this.flushTimer.Set(Ticks.ToTimeSpan(this.flushTimeout)); }
private void ExecuteExports() { byte[] fileData = m_fileData; if (m_enabled && (object)fileData != null && m_exportDestinations.Count > 0) { string fileName = null; ExportState[] exportStates = null; ExportDestination[] destinations; try { // Get a temporary file name fileName = Path.GetTempFileName(); // Export data to the temporary file File.WriteAllBytes(fileName, fileData); lock (m_exportDestinationsLock) { // Cache a local copy of export destinations to reduce lock time destinations = m_exportDestinations.ToArray(); } // Define a new export state for each export destination exportStates = new ExportState[destinations.Length]; for (int i = 0; i < exportStates.Length; i++) { exportStates[i] = new ExportState { SourceFileName = fileName, DestinationFileName = destinations[i].DestinationFile }; } // Spool threads to attempt copy of export files for (int i = 0; i < destinations.Length; i++) { ThreadPool.QueueUserWorkItem(CopyFileToDestination, exportStates[i]); } // Wait for exports to complete - even if user specifies to wait indefinitely spooled copy routines // will eventually return since there is a specified maximum retry count if (!exportStates.Select(exportState => exportState.WaitHandle).WaitAll(m_exportTimeout)) { // Exports failed to complete in specified allowed time, set timeout flag for each export state Array.ForEach(exportStates, exportState => exportState.Timeout = true); OnStatusMessage("Timed out attempting export, waited for {0}.", Ticks.FromMilliseconds(m_exportTimeout).ToElapsedTimeString(2).ToLower()); } } catch (Exception ex) { OnProcessException(new InvalidOperationException($"Exception encountered during export preparation: {ex.Message}", ex)); } finally { // Dispose the export state wait handles if ((object)exportStates != null) { foreach (ExportState exportState in exportStates) { exportState.Dispose(); } } // Delete the temporary file - wait for the specified retry time in case the export threads may still be trying // their last copy attempt. This is important if the timeouts are synchronized and there is one more export // about to be attempted before the timeout flag is checked. new Action(() => DeleteTemporaryFile(fileName)).DelayAndExecute(m_retryDelayInterval); } } }
private static void SynchronizeUsers() { using (Logger.SuppressFirstChanceExceptionLogMessages()) { Dictionary <string, string[]> securityContext = s_latestSecurityContext; if (securityContext is null) { return; } // Skip user synchronization if security context has not changed if (!s_manualSynchronization && SecurityContextsAreEqual(securityContext, s_lastSecurityContext)) { return; } s_manualSynchronization = false; Interlocked.Exchange(ref s_lastSecurityContext, securityContext); // Give initialization - which includes starting Grafana server process - a chance to complete if (!s_initializationWaitHandle.Wait(s_initializationTimeout)) { OnStatusMessage($"WARNING: Grafana user synchronization reported timeout awaiting Grafana initialization. Timeout configured as {Ticks.FromMilliseconds(s_initializationTimeout).ToElapsedTimeString(2)}."); } // Lookup Grafana Administrative user if (!LookupUser(s_adminUser, out UserDetail userDetail, out string message)) { OnStatusMessage($"WARNING: Failed to synchronize Grafana users, cannot find Grafana Administrator \"{s_adminUser}\": {message}"); return; } // Get user list for target organization OrgUserDetail[] organizationUsers = GetOrganizationUsers(s_organizationID, out message); if (!string.IsNullOrEmpty(message)) { OnStatusMessage($"Issue retrieving user list for default organization: {message}"); } // Make sure Grafana Administrator has an admin role in the default organization bool success = organizationUsers.Any(user => user.userId == userDetail.id) ? UpdateUserOrganizationalRole(s_organizationID, userDetail.id, "Admin", out message) : AddUserToOrganization(s_organizationID, s_adminUser, "Admin", out message); if (!success) { OnStatusMessage($"Issue validating organizational admin role for Grafana Administrator \"{s_adminUser}\" - Grafana user synchronization may not succeed: {message}"); } foreach (KeyValuePair <string, string[]> item in securityContext) { string userName = item.Key; string[] roles = item.Value; bool createdUser = false; if (userName.Equals("_logout", StringComparison.OrdinalIgnoreCase)) { continue; } // Check if user exists if (!LookupUser(userName, out userDetail, out message)) { createdUser = CreateUser(userName, s_organizationID, out userDetail, out message); OnStatusMessage($"Encountered new user \"{userName}\": {message}"); } if (userDetail.id == 0) { continue; } // Update user's Grafana admin role status if needed bool userIsGrafanaAdmin = UserIsGrafanaAdmin(roles); if (userDetail.isGrafanaAdmin != userIsGrafanaAdmin) { try { JObject content = JObject.FromObject(new { isGrafanaAdmin = userIsGrafanaAdmin }); message = CallAPIFunction(HttpMethod.Put, $"{s_baseUrl}/api/admin/users/{userDetail.id}/permissions", content.ToString()).Result.message; } catch (Exception ex) { message = ex.Message; } if (!message.Equals("User permissions updated", StringComparison.OrdinalIgnoreCase)) { OnStatusMessage($"Issue updating permissions for user \"{userName}\": {message}"); } } // Attempt to lookup user in default organization OrgUserDetail orgUserDetail = organizationUsers.FirstOrDefault(user => user.userId == userDetail.id); // Get user's organizational role: Admin / Editor / Viewer string organizationalRole = TranslateRole(roles); // Update user's organizational status / role as needed if (orgUserDetail is null && !createdUser) { success = AddUserToOrganization(s_organizationID, userName, organizationalRole, out message); }