private void OnMessage(object sender, EventSource.MessageReceivedEventArgs e) { try { HandleMessage(e.EventName, e.Message.Data); } catch (JsonReadException ex) { _log.Error("LaunchDarkly service request failed or received invalid data: {0}", LogValues.ExceptionSummary(ex)); var errorInfo = new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.InvalidData, Message = ex.Message, Time = DateTime.Now }; _updateSink.UpdateStatus(DataSourceState.Interrupted, errorInfo); _eventSource.Restart(false); } catch (Exception ex) { LogHelpers.LogException(_log, "Unexpected error in stream processing", ex); } }
private async Task UpdateTaskAsync() { try { var response = await _featureFlagRequestor.FeatureFlagsAsync(); if (response.statusCode == 200) { var flagsAsJsonString = response.jsonResponse; var allData = DataModelSerialization.DeserializeV1Schema(flagsAsJsonString); _updateSink.Init(_user, allData); if (_initialized.GetAndSet(true) == false) { _startTask.SetResult(true); _log.Info("Initialized LaunchDarkly Polling Processor."); } } } catch (UnsuccessfulResponseException ex) { var errorInfo = DataSourceStatus.ErrorInfo.FromHttpError(ex.StatusCode); if (HttpErrors.IsRecoverable(ex.StatusCode)) { _log.Warn(HttpErrors.ErrorMessage(ex.StatusCode, "polling request", "will retry")); _updateSink.UpdateStatus(DataSourceState.Interrupted, errorInfo); } else { _log.Error(HttpErrors.ErrorMessage(ex.StatusCode, "polling request", "")); _updateSink.UpdateStatus(DataSourceState.Shutdown, errorInfo); // if client is initializing, make it stop waiting _startTask.TrySetResult(false); ((IDisposable)this).Dispose(); } } catch (JsonReadException ex) { _log.Error("Polling request received malformed data: {0}", LogValues.ExceptionSummary(ex)); _updateSink.UpdateStatus(DataSourceState.Interrupted, new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.InvalidData, Time = DateTime.Now }); } catch (Exception ex) { Exception realEx = (ex is AggregateException ae) ? ae.Flatten() : ex; _log.Warn("Polling for feature flag updates failed: {0}", LogValues.ExceptionSummary(realEx)); _log.Debug(LogValues.ExceptionTrace(realEx)); _updateSink.UpdateStatus(DataSourceState.Interrupted, DataSourceStatus.ErrorInfo.FromException(realEx)); } }
// This method is called while _lock is being held. If we're starting up a new connection, we do // *not* wait for it to succeed; we return a Task that will be completed once it succeeds. In all // other cases we return an immediately-completed Task. private Task <bool> OpenOrCloseConnectionIfNecessary(bool mustReinitializeDataSource) { if (!_started) { return(Task.FromResult(false)); } // Analytics event sending is enabled as long as we're allowed to do any network things. // (If the SDK is configured not to send events, then this is a no-op because _eventProcessor // will be a no-op implementation). _eventProcessor.SetOffline(_forceOffline || !_networkEnabled); // Diagnostic events are disabled if we're in the background. _diagnosticDisabler?.SetDisabled(_forceOffline || !_networkEnabled || _inBackground); if (mustReinitializeDataSource && _dataSource != null) { _dataSource?.Dispose(); _dataSource = null; } if (_networkEnabled && !_forceOffline) { if (_inBackground && !_enableBackgroundUpdating) { _log.Debug("Background updating is disabled"); _updateSink.UpdateStatus(DataSourceState.BackgroundDisabled, null); return(Task.FromResult(true)); } if (_dataSource is null) { // Set the state to Initializing when there's a new data source that has not yet // started. The state will then be updated as appropriate by the data source either // calling UpdateStatus, or Init which implies UpdateStatus(Valid). _updateSink.UpdateStatus(DataSourceState.Initializing, null); _dataSource = _dataSourceFactory.CreateDataSource(_clientContext, _updateSink, _user, _inBackground); return(_dataSource.Start() .ContinueWith(SetInitializedIfUpdateProcessorStartedSuccessfully)); } } else { // Either we've been explicitly set to be offline (in which case the state is always // SetOffline regardless of any other conditions), or we're offline because the network // is unavailable. If either of those things changes, we'll end up calling this method // again and the state will be updated if appropriate. _dataSource?.Dispose(); _dataSource = null; _initialized = true; _updateSink.UpdateStatus( _forceOffline ? DataSourceState.SetOffline : DataSourceState.NetworkUnavailable, null ); return(Task.FromResult(true)); } return(Task.FromResult(false)); }
void Dispose(bool disposing) { if (disposing) { _log.Info("Shutting down the LaunchDarkly client"); _dataSourceUpdateSink.UpdateStatus(DataSourceState.Shutdown, null); _backgroundModeManager.BackgroundModeChanged -= OnBackgroundModeChanged; _connectionManager.Dispose(); _dataStore.Dispose(); _eventProcessor.Dispose(); // Reset the static Instance to null *if* it was referring to this instance DetachInstance(); } }
internal void DoUpdateStatus(DataSourceState newState, DataSourceStatus.ErrorInfo?newError) { _log.Debug("updating status to {0}{1}", newState, newError.HasValue ? (" (" + newError.Value + ")") : ""); _updateSink.UpdateStatus(newState, newError); }