Ejemplo n.º 1
0
        /// <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;
        }
Ejemplo n.º 2
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(FireAsync);
     }
 }
Ejemplo n.º 3
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
            {
                var target        = GetTargetInstance();
                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;
            }
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        public void Reborn_should_not_call_reborn_on_result_if_task_completed_and_just_return_the_returned_phoenixState()
        {
            IPhoenixState reborn = Substitute.For <IPhoenixState>();
            Func <Task <IPhoenixState> > action = () => Task.FromResult(reborn);
            var           state = new RaisingPhoenix();
            IPhoenixState rebornState;

            do
            {
                rebornState = state.Reborn(action);
            } while (object.ReferenceEquals(rebornState, state));

            reborn.Received(0).Reborn(Arg.Any <Func <Task <IPhoenixState> > >());
        }
Ejemplo n.º 6
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)
        {
            _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;
            _timer     = new Timer(_ => Reborn(), null, _info.GetRefreshTime(), TimeSpan.Zero);
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
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);
        }
Ejemplo n.º 9
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);
            
        }
Ejemplo n.º 10
0
        public void Reborn_should_execute_the_task_once()
        {
            var hitCount = 2000;
            var wait     = new AutoResetEvent(false);
            var count    = 0;
            Func <Task <IPhoenixState> > action = () =>
            {
                count++;
                wait.Set();
                IPhoenixState phoenixState = Substitute.For <IPhoenixState>();
                return(Task.FromResult(phoenixState));
            };

            var state = new RaisingPhoenix();

            for (var i = 0; i < hitCount; i++)
            {
                state.Reborn(action);
            }
            Assert.IsTrue(wait.WaitOne(1000));
            Assert.AreEqual(1, count);
        }
Ejemplo n.º 11
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;
            }
        }
Ejemplo n.º 12
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);
     }
 }