示例#1
0
        /// <summary>
        /// Invoked by a Cache instance on updating, using properties from the PollNode such as connection strings, etc.
        /// </summary>
        /// <typeparam name="T">Type of item in the cache</typeparam>
        /// <param name="description">Description of the operation, used purely for profiling</param>
        /// <param name="getData">The operation used to actually get data, e.g. <code>using (var conn = GetConnectionAsync()) { return getFromConnection(conn); }</code></param>
        /// <param name="logExceptions">Whether to log any exceptions to the log</param>
        /// <param name="addExceptionData">Optionally add exception data, e.g. <code>e => e.AddLoggedData("Server", Name)</code></param>
        /// <returns>A cache update action, used when creating a <see cref="Cache"/>.</returns>
        protected Action <Cache <T> > UpdateCacheItem <T>(string description,
                                                          Func <Task <T> > getData,
                                                          bool logExceptions = false, // TODO: Settings
                                                          Action <Exception> addExceptionData = null) where T : class
        {
            return(async cache =>
            {
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    cache.Profiler = OpserverProfileProvider.CreateContextProfiler("Poll: " + description, cache.UniqueId);
                }
                using (MiniProfiler.Current.Step(description))
                {
                    CacheItemFetching?.Invoke(this, EventArgs.Empty);
                    try
                    {
                        using (MiniProfiler.Current.Step("Data Fetch"))
                        {
                            cache.Data = await getData();
                        }
                        cache.LastSuccess = cache.LastPoll = DateTime.UtcNow;
                        cache.ErrorMessage = "";
                        PollFailsInaRow = 0;
                    }
                    catch (Exception e)
                    {
                        var deserializationException = e as DeserializationException;
                        if (deserializationException != null)
                        {
                            e.AddLoggedData("Snippet-After", deserializationException.SnippetAfterError)
                            .AddLoggedData("Position", deserializationException.Position.ToString())
                            .AddLoggedData("Ended-Unexpectedly", deserializationException.EndedUnexpectedly.ToString());
                        }
                        if (logExceptions)
                        {
                            addExceptionData?.Invoke(e);
                            Current.LogException(e);
                        }
                        cache.LastPoll = DateTime.UtcNow;
                        PollFailsInaRow++;
                        cache.ErrorMessage = "Unable to fetch from " + NodeType + ": " + e.Message;
#if DEBUG
                        cache.ErrorMessage += " @ " + e.StackTrace;
#endif

                        if (e.InnerException != null)
                        {
                            cache.ErrorMessage += "\n" + e.InnerException.Message;
                        }
                    }
                    CacheItemFetched?.Invoke(this, EventArgs.Empty);
                    CachedMonitorStatus = null;
                }
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    OpserverProfileProvider.StopContextProfiler();
                }
            });
        }
示例#2
0
        /// <summary>
        /// Invoked by a Cache instance on updating, using properties from the PollNode such as connection strings, etc.
        /// </summary>
        /// <typeparam name="T">Type of item in the cache</typeparam>
        /// <param name="description">Description of the operation, used purely for profiling</param>
        /// <param name="getData">The operation used to actually get data, e.g. <code>using (var conn = GetConnectionAsync()) { return getFromConnection(conn); }</code></param>
        /// <param name="logExceptions">Whether to log any exceptions to the log</param>
        /// <param name="addExceptionData">Optionally add exception data, e.g. <code>e => e.AddLoggedData("Server", Name)</code></param>
        /// <param name="timeoutMs">The timeout in milliseconds for this poll to complete before aborting.</param>
        /// <param name="afterPoll">An optional action to run after polling has completed successfully</param>
        /// <returns>A cache update action, used when creating a <see cref="Cache"/>.</returns>
        protected Func <Cache <T>, Task> UpdateCacheItem <T>(string description,
                                                             Func <Task <T> > getData,
                                                             bool logExceptions = false, // TODO: Settings
                                                             Action <Exception> addExceptionData = null,
                                                             int?timeoutMs = null,
                                                             Action <Cache <T> > afterPoll = null) where T : class
        {
            return(async cache =>
            {
                cache.PollStatus = "UpdateCacheItem";
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    cache.Profiler = OpserverProfileProvider.CreateContextProfiler("Poll: " + description, cache.UniqueId, store: false);
                }
                using (MiniProfiler.Current.Step(description))
                {
                    CacheItemFetching?.Invoke(this, EventArgs.Empty);
                    try
                    {
                        cache.PollStatus = "Fetching";
                        using (MiniProfiler.Current.Step("Data Fetch"))
                        {
                            var fetch = getData();
                            if (timeoutMs.HasValue)
                            {
                                if (await Task.WhenAny(fetch, Task.Delay(timeoutMs.Value)) == fetch)
                                {
                                    // Re-await for throws.
                                    cache.SetData(await fetch.ConfigureAwait(false));
                                }
                                else
                                {
                                    throw new TimeoutException($"Fetch timed out after {timeoutMs.ToString()} ms.");
                                }
                            }
                            else
                            {
                                cache.SetData(await fetch.ConfigureAwait(false));
                            }
                        }
                        cache.PollStatus = "Fetch Complete";
                        cache.SetSuccess();
                        PollFailsInaRow = 0;
                        afterPoll?.Invoke(cache);
                    }
                    catch (Exception e)
                    {
                        if (logExceptions)
                        {
                            addExceptionData?.Invoke(e);
                            Current.LogException(e);
                        }
                        PollFailsInaRow++;
                        var errorMessage = "Unable to fetch from " + NodeType + ": " + e.Message;
#if DEBUG
                        errorMessage += " @ " + e.StackTrace;
#endif
                        if (e.InnerException != null)
                        {
                            errorMessage += "\n" + e.InnerException.Message;
                        }
                        cache.PollStatus = "Fetch Failed";
                        cache.SetFail(errorMessage);
                    }
                    CacheItemFetched?.Invoke(this, EventArgs.Empty);
                    CachedMonitorStatus = null;
                    LastFetch = cache;
                }
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    OpserverProfileProvider.StopContextProfiler();
                }
                cache.PollStatus = "UpdateCacheItem Complete";
            });
        }