/// <summary>
        /// true if the phoenix is executing rebornAction. This is to avoid many call on method Reborn many time
        ///  </summary>


        public IPhoenixState Reborn(Func<Task<IPhoenixState>> rebornAction)
        {
            if (_newPhoenixState != null)
            {
                return _newPhoenixState;
            }

            if (!_startable)
            {
                return this;
            }

            _startable = false;
            Func<Task<IPhoenixState>> wrapper = async () =>
            {
                try
                {
                    var t = rebornAction();
                    _newPhoenixState = await t;
                }
                catch
                {
                    _startable = true;
                }

                return _newPhoenixState;
            };
            Global.BackgroundTaskManager.Run(wrapper);
            
            return this;
        }
Example #2
0
        /// <summary>
        /// Initialize a phoenix with provided cacheDuration and staleWhileRevalidate values
        /// </summary>
        /// <param name="invocation"></param>
        /// <param name="info"></param>
        public Phoenix(_IInvocation invocation, CacheInfo info)
        {
            _info = info;
            _phoenixState = _info.StaleWhileRevalidate > 0 ? (IPhoenixState)new RaisingPhoenix() : new DisposingPhoenix(Die);
            if (invocation.Proxy != null)
            {
                // It is really a dynamic proxy
                _instanceTargetField = invocation.Proxy.GetType().GetField("__target", BindingFlags.Public | BindingFlags.Instance);
            }

            Arguments = invocation.Arguments;
            MethodInfo = invocation.Method;

            _timer = new Timer(_ => Reborn(), null, _info.GetRefreshTime(), TimeSpan.Zero);
        }
Example #3
0
        /// <summary>
        /// Initialize a phoenix with provided cacheDuration and staleWhileRevalidate values
        /// </summary>
        /// <param name="invocation"></param>
        /// <param name="info"></param>
        public Phoenix(_IInvocation invocation, CacheItem info)
        {
            _id = Guid.NewGuid().ToString("N");
            _info = info.CloneWithoutData();
            _phoenixState = _info.StaleWhileRevalidate > 0 ? (IPhoenixState) new InActivePhoenix() : new DisposingPhoenix(DieAsync());
            if (invocation.Proxy != null)
            { 
                // It is really a dynamic proxy
                _instanceTargetField = invocation.Proxy.GetType().GetField("__target", BindingFlags.Public | BindingFlags.Instance);
            }

            Arguments = invocation.Arguments;
            MethodInfo = invocation.Method;

            _allPhoenix[_id] = this;

            //NOTE: Memory leak: http://www.codeproject.com/Questions/185734/Threading-Timer-prevents-GC-collection
            _timer = new Timer(RebornCallback, _id, _info.GetRefreshTime(), TimeSpan.Zero);
            
        }
Example #4
0
        /// <summary>
        /// Rebuild the cache and return the new <see cref="IPhoenixState"/>
        /// </summary>
        /// <returns></returns>
        protected virtual async Task<IPhoenixState> FireAsync()
        {
            MethodInfo.CheckMethodForCacheSupported(out _isAsync);

            try
            {
                using (var dependencyScope = Activator.BeginScope())
                {
                    var target = GetTargetInstance(dependencyScope);
                    var invokedResult = await InvokeAndGetBareResult(target).ConfigureAwait(false);
                    var cacheItem = GetCacheItem(invokedResult);
                    if (cacheItem == null)
                    {
                        var disposing = new DisposingPhoenix(DieAsync());
                        return disposing.Reborn(null);
                    }

                    var cacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(_info.StoreId);
                    //NOTE: Because the cacheItem was created before, the cacheStore cannot be null
                    await cacheStore.SetAsync(_info.Key, cacheItem, DateTime.UtcNow.AddSeconds(_info.MaxAge + _info.StaleWhileRevalidate)).ConfigureAwait(false);

                    Global.Logger.Info($"Updated key \"{_info.Key}\", store \"{_info.StoreId}\"");

                    Retry(_info.GetRefreshTime());
                    _phoenixState = new InActivePhoenix();
                    return _phoenixState;
                }
            }
            catch (Exception ex)
            {
                Global.Logger.Error($"Error while refreshing key {_info.Key}, store \"{_info.StoreId}\". Will retry after 1 second.", ex);
                Retry(TimeSpan.FromSeconds(1));
                throw;
            }
        }
Example #5
0
 /// <summary>
 /// Refresh the cache and change the internal <see cref="IPhoenixState"/> to avoid refreshing too many unnecessary times
 /// <para>The call will happen in background so the caller will not have to wait</para>
 /// </summary>
 public virtual void Reborn()
 {
     lock (PhoenixCage)
     {
         _phoenixState = _phoenixState.Reborn(Fire);
     }
 }