コード例 #1
0
ファイル: TxGrain.cs プロジェクト: fengxing666/Ray
        public override async Task OnActivateAsync()
        {
            await base.OnActivateAsync();

            //如果失活之前已提交事务还没有Complete,则消耗信号量,防止产生新的事物
            if (Snapshot.Base is TxSnapshotBase <PrimaryKey> snapshotBase)
            {
                if (snapshotBase.TransactionId != 0)
                {
                    await TransactionSemaphore.WaitAsync();

                    var waitingEvents = await EventStorage.GetList(GrainId, snapshotBase.TransactionStartTimestamp, snapshotBase.TransactionStartVersion, Snapshot.Base.Version);

                    foreach (var evt in waitingEvents)
                    {
                        var evtType = evt.Event.GetType();
                        WaitingForTransactionTransports.Add(new EventTransport <PrimaryKey>(evt, string.Empty, evt.StateId.ToString())
                        {
                            BytesTransport = new EventBytesTransport(
                                TypeContainer.GetTypeCode(evtType),
                                GrainId,
                                evt.Base.GetBytes(),
                                Serializer.SerializeToUtf8Bytes(evt.Event, evtType)
                                )
                        });
                    }
                    CurrentTransactionId           = snapshotBase.TransactionId;
                    CurrentTransactionStartVersion = snapshotBase.TransactionStartVersion;
                }
            }
            else
            {
                throw new SnapshotNotSupportTxException(Snapshot.GetType());
            }
        }
コード例 #2
0
ファイル: FollowGrain.cs プロジェクト: zszqwe/Ray
        protected async ValueTask Tell(IFullyEvent <PrimaryKey> @event)
        {
            if (Logger.IsEnabled(LogLevel.Trace))
            {
                Logger.LogTrace(LogEventIds.FollowEventProcessing, "Start event handling, grain Id = {0} and state version = {1},event type = {2} ,event = {3}", GrainId.ToString(), Snapshot.Version, @event.GetType().FullName, Serializer.SerializeToString(@event));
            }
            try
            {
                if (@event.Base.Version == Snapshot.Version + 1)
                {
                    var onEventDeliveredTask = OnEventDelivered(@event);
                    if (!onEventDeliveredTask.IsCompletedSuccessfully)
                    {
                        await onEventDeliveredTask;
                    }
                    Snapshot.FullUpdateVersion(@event.Base, GrainType);//更新处理完成的Version
                }
                else if (@event.Base.Version > Snapshot.Version)
                {
                    var eventList = await EventStorage.GetList(GrainId, Snapshot.StartTimestamp, Snapshot.Version + 1, @event.Base.Version - 1);

                    foreach (var evt in eventList)
                    {
                        var onEventDeliveredTask = OnEventDelivered(evt);
                        if (!onEventDeliveredTask.IsCompletedSuccessfully)
                        {
                            await onEventDeliveredTask;
                        }
                        Snapshot.FullUpdateVersion(evt.Base, GrainType);//更新处理完成的Version
                    }
                }
                if (@event.Base.Version == Snapshot.Version + 1)
                {
                    var onEventDeliveredTask = OnEventDelivered(@event);
                    if (!onEventDeliveredTask.IsCompletedSuccessfully)
                    {
                        await onEventDeliveredTask;
                    }
                    Snapshot.FullUpdateVersion(@event.Base, GrainType);//更新处理完成的Version
                }
                if (@event.Base.Version > Snapshot.Version)
                {
                    throw new EventVersionNotMatchStateException(GrainId.ToString(), GrainType, @event.Base.Version, Snapshot.Version);
                }
                await SaveSnapshotAsync();

                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace(LogEventIds.FollowEventProcessing, "Event Handling Completion, grain Id ={0} and state version = {1},event type = {2}", GrainId.ToString(), Snapshot.Version, @event.GetType().FullName);
                }
            }
            catch (Exception ex)
            {
                if (Logger.IsEnabled(LogLevel.Critical))
                {
                    Logger.LogCritical(LogEventIds.FollowEventProcessing, ex, "FollowGrain Event handling failed with Id = {0},event = {1}", GrainId.ToString(), Serializer.SerializeToString(@event));
                }
                throw;
            }
        }
コード例 #3
0
        public override async Task OnActivateAsync()
        {
            await base.OnActivateAsync();

            //如果失活之前已提交事务还没有Complete,则消耗信号量,防止产生新的事物
            if (Snapshot.Base.TransactionId != 0)
            {
                await TransactionSemaphore.WaitAsync();

                var waitingEvents = await EventStorage.GetList(GrainId, Snapshot.Base.TransactionStartTimestamp, Snapshot.Base.TransactionStartVersion, Snapshot.Base.Version);

                foreach (var evt in waitingEvents)
                {
                    WaitingForTransactionTransports.Add(new EventTransport <PrimaryKey>(evt, string.Empty, evt.StateId.ToString())
                    {
                        BytesTransport = new EventBytesTransport
                        {
                            EventType  = evt.Event.GetType().FullName,
                            GrainId    = GrainId,
                            EventBytes = Serializer.SerializeToBytes(evt.Event),
                            BaseBytes  = evt.Base.GetBytes()
                        }
                    });
                }
                CurrentTransactionId           = Snapshot.Base.TransactionId;
                CurrentTransactionStartVersion = Snapshot.Base.TransactionStartVersion;
            }
        }
コード例 #4
0
        private async Task FullActive()
        {
            while (true)
            {
                var eventList = await EventStorage.GetList(GrainId, Snapshot.StartTimestamp, Snapshot.Version + 1, Snapshot.Version + ConfigOptions.NumberOfEventsPerRead);

                if (EventConcurrentProcessing)
                {
                    await Task.WhenAll(eventList.Select(@event =>
                    {
                        var task = OnEventDelivered(@event);
                        if (!task.IsCompletedSuccessfully)
                        {
                            return(task.AsTask());
                        }
                        else
                        {
                            return(Task.CompletedTask);
                        }
                    }));

                    var lastEvt = eventList.Last();
                    Snapshot.UnsafeUpdateVersion(lastEvt.Base);
                }
                else
                {
                    foreach (var @event in eventList)
                    {
                        Snapshot.IncrementDoingVersion(GrainType);//标记将要处理的Version
                        var task = OnEventDelivered(@event);
                        if (!task.IsCompletedSuccessfully)
                        {
                            await task;
                        }
                        Snapshot.UpdateVersion(@event.Base, GrainType);//更新处理完成的Version
                    }
                }
                var saveTask = SaveSnapshotAsync();
                if (!saveTask.IsCompletedSuccessfully)
                {
                    await saveTask;
                }
                if (eventList.Count < ConfigOptions.NumberOfEventsPerRead)
                {
                    break;
                }
            }
            ;
        }
コード例 #5
0
        protected async ValueTask Tell(IFullyEvent <PrimaryKey> @event)
        {
            try
            {
                if (@event.Base.Version == Snapshot.Base.Version + 1)
                {
                    var onEventDeliveredTask = OnEventDelivered(@event);
                    if (!onEventDeliveredTask.IsCompletedSuccessfully)
                    {
                        await onEventDeliveredTask;
                    }
                    Snapshot.Base.FullUpdateVersion(@event.Base, GrainType);//更新处理完成的Version
                }
                else if (@event.Base.Version > Snapshot.Base.Version)
                {
                    var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.StartTimestamp, Snapshot.Base.Version + 1, @event.Base.Version - 1);

                    foreach (var evt in eventList)
                    {
                        var onEventDeliveredTask = OnEventDelivered(evt);
                        if (!onEventDeliveredTask.IsCompletedSuccessfully)
                        {
                            await onEventDeliveredTask;
                        }
                        Snapshot.Base.FullUpdateVersion(evt.Base, GrainType);//更新处理完成的Version
                    }
                }
                if (@event.Base.Version == Snapshot.Base.Version + 1)
                {
                    var onEventDeliveredTask = OnEventDelivered(@event);
                    if (!onEventDeliveredTask.IsCompletedSuccessfully)
                    {
                        await onEventDeliveredTask;
                    }
                    Snapshot.Base.FullUpdateVersion(@event.Base, GrainType);//更新处理完成的Version
                }
                if (@event.Base.Version > Snapshot.Base.Version)
                {
                    throw new EventVersionUnorderedException(GrainId.ToString(), GrainType, @event.Base.Version, Snapshot.Base.Version);
                }
            }
            catch (Exception ex)
            {
                Logger.LogCritical(ex, "{0}({1})", @event.GetType().FullName, Serializer.Serialize(@event, @event.GetType()));
                throw;
            }
        }
コード例 #6
0
        public override async Task OnActivateAsync()
        {
            var dITask = DependencyInjection();

            if (!dITask.IsCompletedSuccessfully)
            {
                await dITask;
            }
            try
            {
                if (ArchiveOptions.On)
                {
                    //加载最后一条归档
                    LastArchive = await ArchiveStorage.GetLatestBrief(GrainId);
                }
                await ReadSnapshotAsync();

                if (FullyActive)
                {
                    while (true)
                    {
                        var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.StartTimestamp, Snapshot.Base.Version + 1, Snapshot.Base.Version + NumberOfEventsPerRead);

                        var task = Tell(eventList);
                        if (!task.IsCompletedSuccessfully)
                        {
                            await task;
                        }
                        if (eventList.Count < NumberOfEventsPerRead)
                        {
                            break;
                        }
                    }
                    ;
                }
                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace("Activation completed: {0}->{1}", GrainType.FullName, Serializer.Serialize(Snapshot));
                }
            }
            catch (Exception ex)
            {
                Logger.LogCritical(ex, "Activation failed: {0}->{1}", GrainType.FullName, GrainId.ToString());
                throw;
            }
        }
コード例 #7
0
ファイル: ShadowGrain.cs プロジェクト: zhaoshuaihui/Ray
        /// <summary>
        /// 从库里恢复
        /// </summary>
        /// <returns></returns>
        private async Task RecoveryFromStorage()
        {
            while (true)
            {
                var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.StartTimestamp, Snapshot.Base.Version + 1, Snapshot.Base.Version + NumberOfEventsPerRead);

                var task = Tell(eventList);
                if (!task.IsCompletedSuccessfully)
                {
                    await task;
                }
                if (eventList.Count < NumberOfEventsPerRead)
                {
                    break;
                }
            }
            ;
        }
コード例 #8
0
        protected virtual async Task RecoverySnapshot()
        {
            try
            {
                await ReadSnapshotAsync();

                while (!Snapshot.Base.IsLatest)
                {
                    var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.LatestMinEventTimestamp, Snapshot.Base.Version + 1, Snapshot.Base.Version + CoreOptions.NumberOfEventsPerRead);

                    foreach (var fullyEvent in eventList)
                    {
                        Snapshot.Base.IncrementDoingVersion(GrainType);          //标记将要处理的Version
                        SnapshotHandler.Apply(Snapshot, fullyEvent);
                        Snapshot.Base.UpdateVersion(fullyEvent.Base, GrainType); //更新处理完成的Version
                    }
                    if (eventList.Count < CoreOptions.NumberOfEventsPerRead)
                    {
                        break;
                    }
                }
                ;
                if (Snapshot.Base.Version - SnapshotEventVersion >= CoreOptions.MinSnapshotVersionInterval)
                {
                    var saveTask = SaveSnapshotAsync(true, true);
                    if (!saveTask.IsCompletedSuccessfully)
                    {
                        await saveTask;
                    }
                }
                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace("Recovery completed: {0}->{1}", GrainType.FullName, Serializer.Serialize(Snapshot));
                }
            }
            catch (Exception ex)
            {
                Logger.LogCritical(ex, "Recovery failed: {0}->{1}", GrainType.FullName, GrainId.ToString());
                throw;
            }
        }
コード例 #9
0
ファイル: ShadowGrain.cs プロジェクト: changweihua/Ray
        protected async ValueTask Tell(IFullyEvent <PrimaryKey> @event)
        {
            if (@event.Base.Version == Snapshot.Base.Version + 1)
            {
                var onEventDeliveredTask = OnEventDelivered(@event);
                if (!onEventDeliveredTask.IsCompletedSuccessfully)
                {
                    await onEventDeliveredTask;
                }
                Snapshot.Base.FullUpdateVersion(@event.Base, GrainType);//更新处理完成的Version
            }
            else if (@event.Base.Version > Snapshot.Base.Version)
            {
                var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.StartTimestamp, Snapshot.Base.Version + 1, @event.Base.Version - 1);

                foreach (var evt in eventList)
                {
                    var onEventDeliveredTask = OnEventDelivered(evt);
                    if (!onEventDeliveredTask.IsCompletedSuccessfully)
                    {
                        await onEventDeliveredTask;
                    }
                    Snapshot.Base.FullUpdateVersion(evt.Base, GrainType);//更新处理完成的Version
                }
            }
            if (@event.Base.Version == Snapshot.Base.Version + 1)
            {
                var onEventDeliveredTask = OnEventDelivered(@event);
                if (!onEventDeliveredTask.IsCompletedSuccessfully)
                {
                    await onEventDeliveredTask;
                }
                Snapshot.Base.FullUpdateVersion(@event.Base, GrainType);//更新处理完成的Version
            }
            if (@event.Base.Version > Snapshot.Base.Version)
            {
                throw new EventVersionUnorderedException(GrainId.ToString(), GrainType, @event.Base.Version, Snapshot.Base.Version);
            }
        }
コード例 #10
0
ファイル: ReplicaGrain.cs プロジェクト: pangfd/Ray
        private async Task FullActive()
        {
            while (true)
            {
                var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.StartTimestamp, Snapshot.Base.Version + 1, Snapshot.Base.Version + NumberOfEventsPerRead);

                foreach (var @event in eventList)
                {
                    Snapshot.Base.IncrementDoingVersion(GrainType);//标记将要处理的Version
                    var task = OnEventDelivered(@event);
                    if (!task.IsCompletedSuccessfully)
                    {
                        await task;
                    }
                    Snapshot.Base.UpdateVersion(@event.Base, GrainType);//更新处理完成的Version
                }
                if (eventList.Count < NumberOfEventsPerRead)
                {
                    break;
                }
            }
            ;
        }
コード例 #11
0
ファイル: RayGrain.cs プロジェクト: vuongthai91/Ray
        protected virtual async Task RecoverySnapshot()
        {
            if (Logger.IsEnabled(LogLevel.Trace))
            {
                Logger.LogTrace("The state of id = {0} begin to recover", GrainId.ToString());
            }
            try
            {
                await ReadSnapshotAsync();

                while (!Snapshot.Base.IsLatest)
                {
                    var eventList = await EventStorage.GetList(GrainId, Snapshot.Base.LatestMinEventTimestamp, Snapshot.Base.Version + 1, Snapshot.Base.Version + CoreOptions.NumberOfEventsPerRead);

                    foreach (var fullyEvent in eventList)
                    {
                        Snapshot.Base.IncrementDoingVersion(GrainType);          //标记将要处理的Version
                        EventHandler.Apply(Snapshot, fullyEvent);
                        Snapshot.Base.UpdateVersion(fullyEvent.Base, GrainType); //更新处理完成的Version
                    }
                    if (eventList.Count < CoreOptions.NumberOfEventsPerRead)
                    {
                        break;
                    }
                }
                ;
                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace("The state of id = {0} recovery has been completed ,state version = {1}", GrainId.ToString(), Snapshot.Base.Version);
                }
            }
            catch (Exception ex)
            {
                Logger.LogCritical(ex, "The state of id = {0} recovery has failed ,state version = {1}", GrainId.ToString(), Snapshot.Base.Version);
                throw;
            }
        }
コード例 #12
0
ファイル: RayGrain.cs プロジェクト: vuongthai91/Ray
        /// <summary>
        /// Grain激活时调用用来初始化的方法(禁止在子类重写,请使用)
        /// </summary>
        /// <returns></returns>
        public override async Task OnActivateAsync()
        {
            var dITask = DependencyInjection();

            if (Logger.IsEnabled(LogLevel.Trace))
            {
                Logger.LogTrace("Start activation with id = {0}", GrainId.ToString());
            }
            if (!dITask.IsCompletedSuccessfully)
            {
                await dITask;
            }
            try
            {
                if (ArchiveOptions.On)
                {
                    //加载归档信息
                    BriefArchiveList = (await ArchiveStorage.GetBriefList(GrainId)).OrderBy(a => a.Index).ToList();
                    LastArchive      = BriefArchiveList.LastOrDefault();
                    ClearedArchive   = BriefArchiveList.Where(a => a.EventIsCleared).OrderByDescending(a => a.Index).FirstOrDefault();
                    var secondLastArchive = BriefArchiveList.Count > 1 ? BriefArchiveList.SkipLast(1).Last() : default;
                    if (LastArchive != default && !LastArchive.IsCompletedArchive(ArchiveOptions, secondLastArchive) && !LastArchive.EventIsCleared)
                    {
                        await DeleteArchive(LastArchive.Id);

                        BriefArchiveList.Remove(LastArchive);
                        NewArchive  = LastArchive;
                        LastArchive = BriefArchiveList.LastOrDefault();
                    }
                }
                //修复状态
                await RecoverySnapshot();

                if (ArchiveOptions.On)
                {
                    if (Snapshot.Base.Version != 0 &&
                        (LastArchive == default || LastArchive.EndVersion < Snapshot.Base.Version) &&
                        (NewArchive == default || NewArchive.EndVersion < Snapshot.Base.Version))
                    {
                        //归档恢复
                        while (true)
                        {
                            var  startTimestamp = Snapshot.Base.StartTimestamp;
                            long startVersion   = 0;
                            if (NewArchive != default)
                            {
                                startVersion   = NewArchive.EndVersion;
                                startTimestamp = NewArchive.StartTimestamp;
                            }
                            else if (NewArchive == default && LastArchive != default)
                            {
                                startVersion   = LastArchive.EndVersion;
                                startTimestamp = LastArchive.EndTimestamp;
                            }
                            var eventList = await EventStorage.GetList(GrainId, startTimestamp, startVersion + 1, startVersion + CoreOptions.NumberOfEventsPerRead);

                            foreach (var @event in eventList)
                            {
                                var task = EventArchive(@event);
                                if (!task.IsCompletedSuccessfully)
                                {
                                    await task;
                                }
                            }
                            if (eventList.Count < CoreOptions.NumberOfEventsPerRead)
                            {
                                break;
                            }
                        }
                        ;
                    }
                }
                var onActivatedTask = OnBaseActivated();
                if (!onActivatedTask.IsCompletedSuccessfully)
                {
                    await onActivatedTask;
                }
                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace("Activation completed with id = {0}", GrainId.ToString());
                }
            }
            catch (Exception ex)
            {
                Logger.LogCritical(ex, "Activation failed with Id = {0}", GrainId.ToString());
                throw;
            }
        }
コード例 #13
0
        private async Task BatchInputProcessing(List <AsyncInputEvent <IFullyEvent <PrimaryKey>, bool> > eventInputs)
        {
            var evtList      = new List <IFullyEvent <PrimaryKey> >();
            var startVersion = Snapshot.Version;

            if (UnprocessedEventList.Count > 0)
            {
                startVersion = UnprocessedEventList.Last().Base.Version;
            }
            var maxVersion = startVersion;
            TaskCompletionSource <bool> maxRequest = default;

            try
            {
                foreach (var input in eventInputs)
                {
                    if (input.Value.Base.Version == startVersion)
                    {
                        maxRequest = input.TaskSource;
                    }
                    else if (input.Value.Base.Version < startVersion)
                    {
                        input.TaskSource.TrySetResult(true);
                    }
                    else
                    {
                        evtList.Add(input.Value);
                        if (input.Value.Base.Version > maxVersion)
                        {
                            maxRequest?.TrySetResult(true);
                            maxVersion = input.Value.Base.Version;
                            maxRequest = input.TaskSource;
                        }
                        else
                        {
                            input.TaskSource.TrySetResult(true);
                        }
                    }
                }

                if (evtList.Count > 0)
                {
                    var orderList = evtList.OrderBy(e => e.Base.Version).ToList();
                    var inputLast = orderList.Last();
                    if (startVersion + orderList.Count < inputLast.Base.Version)
                    {
                        var loadList = await EventStorage.GetList(GrainId, 0, startVersion + 1, inputLast.Base.Version - 1);

                        UnprocessedEventList.AddRange(loadList);
                        UnprocessedEventList.Add(inputLast);
                    }
                    else
                    {
                        UnprocessedEventList.AddRange(orderList.Select(w => w));
                    }
                }
                if (UnprocessedEventList.Count > 0)
                {
                    await Task.WhenAll(UnprocessedEventList.Select(async @event =>
                    {
                        var task = EventDelivered(@event);
                        if (!task.IsCompletedSuccessfully)
                        {
                            await task;
                        }
                    }));

                    Snapshot.UnsafeUpdateVersion(UnprocessedEventList.Last().Base);
                    var saveTask = SaveSnapshotAsync();
                    if (!saveTask.IsCompletedSuccessfully)
                    {
                        await saveTask;
                    }
                    UnprocessedEventList.Clear();
                    maxRequest?.TrySetResult(true);
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "FollowGrain event handling failed with Id {1}", GrainId.ToString());
                maxRequest?.TrySetException(ex);
            }
        }
コード例 #14
0
        private async Task BatchInputProcessing(List <DataAsyncWrapper <IFullyEvent <PrimaryKey>, bool> > events)
        {
            var evtList      = new List <IFullyEvent <PrimaryKey> >();
            var startVersion = Snapshot.Version;

            if (UnprocessedEventList.Count > 0)
            {
                startVersion = UnprocessedEventList.Last().Base.Version;
            }
            var maxVersion = startVersion;
            TaskCompletionSource <bool> maxRequest = default;

            try
            {
                foreach (var wrap in events)
                {
                    if (wrap.Value.Base.Version <= startVersion)
                    {
                        wrap.TaskSource.TrySetResult(true);
                    }
                    else
                    {
                        evtList.Add(wrap.Value);
                        if (wrap.Value.Base.Version > maxVersion)
                        {
                            maxRequest?.TrySetResult(true);
                            maxVersion = wrap.Value.Base.Version;
                            maxRequest = wrap.TaskSource;
                        }
                        else
                        {
                            wrap.TaskSource.TrySetResult(true);
                        }
                    }
                }
                var orderList = evtList.OrderBy(e => e.Base.Version).ToList();
                if (orderList.Count > 0)
                {
                    var inputLast = orderList.Last();
                    if (startVersion + orderList.Count < inputLast.Base.Version)
                    {
                        var loadList = await EventStorage.GetList(GrainId, 0, startVersion + 1, inputLast.Base.Version - 1);

                        UnprocessedEventList.AddRange(loadList);
                    }
                    else
                    {
                        UnprocessedEventList.AddRange(orderList.Select(w => w));
                    }
                }
                if (UnprocessedEventList.Count > 0)
                {
                    using (var tokenSource = new CancellationTokenSource())
                    {
                        var allTask = Task.WhenAll(UnprocessedEventList.Select(@event =>
                        {
                            var task = OnEventDelivered(@event);
                            if (!task.IsCompletedSuccessfully)
                            {
                                return(task.AsTask());
                            }
                            else
                            {
                                return(Task.CompletedTask);
                            }
                        }));
                        using (var delayTask = Task.Delay(ConfigOptions.EventAsyncProcessTimeoutSeconds, tokenSource.Token))
                        {
                            await Task.WhenAny(allTask, delayTask);

                            if (allTask.Status == TaskStatus.RanToCompletion)
                            {
                                tokenSource.Cancel();
                                var lastEvt     = UnprocessedEventList.Last();
                                var lastEvtBase = lastEvt.Base;
                                Snapshot.UnsafeUpdateVersion(lastEvtBase);
                                var saveTask = SaveSnapshotAsync();
                                if (!saveTask.IsCompletedSuccessfully)
                                {
                                    await saveTask;
                                }
                                UnprocessedEventList.Clear();
                                maxRequest?.TrySetResult(true);
                            }
                            else
                            {
                                maxRequest?.TrySetException(timeoutException);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "FollowGrain event handling failed with Id {1}", GrainId.ToString());
                maxRequest?.TrySetException(ex);
            }
        }