예제 #1
0
 /// <summary>
 /// Adds a node to the global polling list ONLY IF IT IS NEW
 /// If a node with the same unique key was already added, it will not be added again
 /// </summary>
 /// <param name="node">The node to add to the global polling list</param>
 /// <returns>Whether the node was added</returns>
 public static bool TryAdd(PollNode node)
 {
     lock (_addLock)
     {
         return AllPollNodes.Add(node);
     }
 }
예제 #2
0
 /// <summary>
 /// Adds a node to the global polling list ONLY IF IT IS NEW
 /// If a node with the same unique key was already added, it will not be added again
 /// </summary>
 /// <param name="node">The node to add to the global polling list</param>
 /// <returns>Whether the node was added</returns>
 public static bool TryAdd(PollNode node)
 {
     lock (_addLock)
     {
         return(AllPollNodes.Add(node));
     }
 }
예제 #3
0
 public static bool TryRemove(PollNode node)
 {
     if (node == null || !node.AddedToGlobalPollers) return false;
     lock (_addLock)
     {
         return AllPollNodes.Remove(node);
     }
 }
예제 #4
0
 public static NodeData FromNode(PollNode node, bool includeCache = false)
 {
     return(new NodeData
     {
         Name = node.UniqueKey,
         Type = node.NodeType,
         LastPolled = node.LastPoll,
         LastPollDurationMS = node.LastPollDuration.TotalMilliseconds,
         Caches = node.DataPollers.Select(c => CacheData.FromCache(c, includeCache))
     });
 }
예제 #5
0
 public static bool TryRemove(PollNode node)
 {
     if (node == null || !node.AddedToGlobalPollers)
     {
         return(false);
     }
     lock (_addLock)
     {
         return(AllPollNodes.Remove(node));
     }
 }
예제 #6
0
 public static NodeData FromNode(PollNode node, bool includeCache = false)
 {
     return new NodeData
         {
             Name = node.UniqueKey,
             Type = node.NodeType,
             LastPolled = node.LastPoll,
             LastPollDurationMS = node.LastPollDuration.TotalMilliseconds,
             Caches = node.DataPollers.Select(c => CacheData.FromCache(c, includeCache))
         };
 }
예제 #7
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 = null,
                     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; // concatenate once
            // TODO: Settings via owner
            logExceptions = logExceptions ?? LogExceptions;

            _updateFunc = async() =>
            {
                var success = true;
                PollStatus = "UpdateCacheItem";
                if (EnableProfiling)
                {
                    Profiler    = _profilerOptions.StartProfiler(MiniProfilerDescription);
                    Profiler.Id = UniqueId;
                }
                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)) == 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.Value)
                        {
                            addExceptionData?.Invoke(e);
                            e.Log();
                        }
                        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 (EnableProfiling)
                {
                    Profiler.Stop();
                }
                PollStatus = "UpdateCacheItem Complete";
                return(Data);
            };
        }