Esempio n. 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();
                }
            });
        }
Esempio n. 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";
            });
        }
Esempio n. 3
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 = GetConnection()) { 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 <T> getData,
                                                          bool logExceptions = false, // TODO: Settings
                                                          Action <Exception> addExceptionData = null) where T : class
        {
            return(cache =>
            {
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    cache.Profiler = OpserverProfileProvider.CreateContextProfiler("Poll: " + description, cache.UniqueId);
                }
                using (MiniProfiler.Current.Step(description))
                {
                    if (CacheItemFetching != null)
                    {
                        CacheItemFetching(this, EventArgs.Empty);
                    }
                    try
                    {
                        using (MiniProfiler.Current.Step("Data Fetch"))
                        {
                            cache.Data = getData();
                        }
                        cache.LastSuccess = cache.LastPoll = DateTime.UtcNow;
                        cache.ErrorMessage = "";
                        PollFailsInaRow = 0;
                    }
                    catch (Exception e)
                    {
                        if (logExceptions)
                        {
                            if (addExceptionData != null)
                            {
                                addExceptionData(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;
                        }
                    }
                    if (CacheItemFetched != null)
                    {
                        CacheItemFetched(this, EventArgs.Empty);
                    }
                    CachedMonitorStatus = null;
                }
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    OpserverProfileProvider.StopContextProfiler();
                }
            });
        }
Esempio n. 4
0
        /// <summary>
        /// Creates a cache poller
        /// </summary>
        /// <typeparam name="T">Type of item in the cache</typeparam>
        /// <param name="owner">The PollNode owner of this Cache</param>
        /// <param name="description">Description of the operation, used purely for profiling</param>
        /// <param name="cacheDuration">The length of time to cache data for</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="timeoutMs">The timeout in milliseconds for this poll to complete before aborting.</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="afterPoll">An optional action to run after polling has completed successfully</param>
        /// <param name="memberName"></param>
        /// <param name="sourceFilePath"></param>
        /// <param name="sourceLineNumber"></param>
        /// <returns>A cache update action, used when creating a <see cref="Cache"/>.</returns>
        public Cache(PollNode owner,
                     string description,
                     TimeSpan cacheDuration,
                     Func <Task <T> > getData,
                     int?timeoutMs      = null,
                     bool logExceptions = false, // TODO: Settings
                     Action <Exception> addExceptionData     = null,
                     Action <Cache <T> > afterPoll           = null,
                     [CallerMemberName] string memberName    = "",
                     [CallerFilePath] string sourceFilePath  = "",
                     [CallerLineNumber] int sourceLineNumber = 0)
            : base(cacheDuration, memberName, sourceFilePath, sourceLineNumber)
        {
            MiniProfilerDescription = "Poll: " + description; // contcat once

            _updateFunc = async() =>
            {
                var success = true;
                PollStatus = "UpdateCacheItem";
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    Profiler = OpserverProfileProvider.CreateContextProfiler(MiniProfilerDescription, UniqueId,
                                                                             store: false);
                }
                using (MiniProfiler.Current.Step(description))
                {
                    try
                    {
                        PollStatus = "Fetching";
                        using (MiniProfiler.Current.Step("Data Fetch"))
                        {
                            var task = getData();
                            if (timeoutMs.HasValue)
                            {
                                if (await Task.WhenAny(task, Task.Delay(timeoutMs.Value)).ConfigureAwait(false) == task)
                                {
                                    // Re-await for throws.
                                    Data = await task;
                                }
                                else
                                {
                                    // This means the whenany returned the timeout first...boom.
                                    throw new TimeoutException($"Fetch timed out after {timeoutMs} ms.");
                                }
                            }
                            else
                            {
                                Data = await task;
                            }
                        }
                        PollStatus = "Fetch Complete";
                        SetSuccess();
                        afterPoll?.Invoke(this);
                    }
                    catch (Exception e)
                    {
                        success = false;
                        if (logExceptions)
                        {
                            addExceptionData?.Invoke(e);
                            Current.LogException(e);
                        }
                        var errorMessage = StringBuilderCache.Get()
                                           .Append("Unable to fetch from ")
                                           .Append(owner.NodeType)
                                           .Append(": ")
                                           .Append(e.Message);
#if DEBUG
                        errorMessage.Append(" @ ").Append(e.StackTrace);
#endif
                        if (e.InnerException != null)
                        {
                            errorMessage.AppendLine().Append(e.InnerException.Message);
                        }
                        PollStatus = "Fetch Failed";
                        SetFail(e, errorMessage.ToStringRecycle());
                    }
                    owner.PollComplete(this, success);
                }
                if (OpserverProfileProvider.EnablePollerProfiling)
                {
                    OpserverProfileProvider.StopContextProfiler();
                }
                PollStatus = "UpdateCacheItem Complete";
                return(Data);
            };
        }