示例#1
0
 // Temp: all async when views can be in MVC Core
 public static LightweightCache <T> Get(PollNode owner, string key, Func <T> getData, TimeSpan duration, TimeSpan staleDuration)
 {
     using (MiniProfiler.Current.Step("LightweightCache: " + key))
     {
         // Let GetSet handle the overlap and locking, for now. That way it's store dependent.
         return(owner.MemCache.GetSet <LightweightCache <T> >(key, (_, __) =>
         {
             var tc = new LightweightCache <T>()
             {
                 Key = key
             };
             try
             {
                 tc.Data = getData();
             }
             catch (Exception e)
             {
                 tc.Error = e;
                 e.Log();
             }
             tc.LastFetch = DateTime.UtcNow;
             return tc;
         }, duration, staleDuration));
     }
 }
示例#2
0
 public NodeData(PollNode node, bool includeData = false)
 {
     Name               = node.UniqueKey;
     Type               = node.NodeType;
     LastPolled         = node.LastPoll;
     LastPollDurationMS = node.LastPollDuration.TotalMilliseconds;
     Caches             = node.DataPollers.Select(c => new CacheData(c, includeData));
 }
示例#3
0
 public bool TryRemove(PollNode node)
 {
     if (node == null || !node.AddedToGlobalPollers)
     {
         return(false);
     }
     lock (_addLock)
     {
         return(AllPollNodes.Remove(node));
     }
 }
示例#4
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 bool TryAdd(PollNode node)
 {
     lock (_addLock)
     {
         var success = AllPollNodes.Add(node);
         if (success)
         {
             if (node is IIssuesProvider iProvider)
             {
                 IssueProviders.Add(iProvider);
             }
             if (node is INodeRoleProvider nrProvider)
             {
                 NodeRoleProviders.Add(nrProvider);
             }
         }
         return(success);
     }
 }
示例#5
0
 public static NodeData GetNode(PollNode node, bool includeData = false) => new NodeData(node, includeData);
示例#6
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(owner, cacheDuration, memberName, sourceFilePath, sourceLineNumber)
        {
            MiniProfilerDescription = "Poll: " + description; // concatenate once
            // TODO: Settings via owner
            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);
            };
        }