public ProcessResult Process(TcpPackage package)
        {
            try
            {
                if (package.Command != TcpCommand.ReadEventsFromBeginningCompleted)
                {
                    return new ProcessResult(ProcessResultStatus.NotifyError, 
                                             new Exception(string.Format("Not expected command, expected {0}, received {1}",  
                                                                         TcpCommand.ReadEventsFromBeginningCompleted, package.Command)));
                }

                var data = package.Data;
                var dto = data.Deserialize<ClientMessageDto.ReadEventsFromBeginningCompleted>();
                _resultDto = dto;

                switch ((RangeReadResult)dto.Result)
                {
                    case RangeReadResult.Success:
                        return new ProcessResult(ProcessResultStatus.Success);
                    case RangeReadResult.StreamDeleted:
                    case RangeReadResult.NoStream:
                        return new ProcessResult(ProcessResultStatus.NotifyError, 
                                                 new Exception(string.Format("{0}", (RangeReadResult)dto.Result)));
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
            catch (Exception ex)
            {
                return new ProcessResult(ProcessResultStatus.NotifyError, ex);
            }
        }
        public WorkItem(TcpPackage tcpPackage)
        {
            TcpPackage = tcpPackage;

            Attempt = 0;
            LastUpdatedTicks = DateTime.UtcNow.Ticks;
        }
        public bool UpdateForNextAttempt()
        {
            _resultDto = null;

            var correlationId = Guid.NewGuid();
            Attempt += 1;
            var package = new TcpPackage(SentPackage.Command, correlationId, SentPackage.Data);
            SentPackage = package;

            return true;
        }
        public ProcessResult Process(TcpPackage package)
        {
            try
            {
                if (package.Command != TcpCommand.WriteEventsCompleted)
                {
                    return new ProcessResult(ProcessResultStatus.NotifyError, 
                                             new Exception(string.Format("Not expected command, expected {0}, received {1}",  
                                                                         TcpCommand.WriteEventsCompleted, package.Command)));
                }

                var data = package.Data;
                var dto = data.Deserialize<ClientMessageDto.WriteEventsCompleted>();
                _resultDto = dto;

                switch ((OperationErrorCode)dto.ErrorCode)
                {
                    case OperationErrorCode.Success:
                        return new ProcessResult(ProcessResultStatus.Success);

                    case OperationErrorCode.PrepareTimeout:
                    case OperationErrorCode.CommitTimeout:
                    case OperationErrorCode.ForwardTimeout:
                        if (Attempt < MaxRetriesCount)
                        {
                            return new ProcessResult(ProcessResultStatus.Retry);
                        }
                        else
                        {
                            return new ProcessResult(ProcessResultStatus.NotifyError, 
                                                     new Exception(string.Format("Max retries count reached, last error: {0}", 
                                                                  (OperationErrorCode)dto.ErrorCode)));
                        }
                    case OperationErrorCode.WrongExpectedVersion:
                    case OperationErrorCode.StreamDeleted:
                    case OperationErrorCode.InvalidTransaction:
                        return new ProcessResult(ProcessResultStatus.NotifyError, 
                                                 new Exception(string.Format("{0}", (OperationErrorCode)dto.ErrorCode)));
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
            catch (Exception ex)
            {
                return new ProcessResult(ProcessResultStatus.NotifyError, ex);
            }
        }
        private void Retry(Guid correlationId)
        {
            //lock (_connectionLock)
            {
                WorkItem inProgressItem;
                ITaskCompletionWrapper wrapper;

                if (RemoveInProgressItem(correlationId, " IN Retry", out inProgressItem, out wrapper))
                {
                    var newCorrelationId = Guid.NewGuid();
                    var newPackage = new TcpPackage(inProgressItem.TcpPackage.Command, 
                                                    newCorrelationId,
                                                    inProgressItem.TcpPackage.Data);
                    inProgressItem.Attempt += 1;
                    inProgressItem.TcpPackage = newPackage;
                    Interlocked.Exchange(ref inProgressItem.LastUpdatedTicks, DateTime.UtcNow.Ticks);

                    if (inProgressItem.Attempt > 100)
                    {
                       wrapper.Fail(new Exception(string.Format("Item's {0} current attempt is {1}!",
                                                                            inProgressItem,
                                                                            inProgressItem.Attempt)));
                    }
                    else
                    {
                            wrapper.SentPackage = newPackage;
                            Send(inProgressItem, wrapper);
                    }
                }
                else
                {
                    ITaskCompletionWrapper completionWrapper;
                    if (_outstandingOperations.TryRemove(correlationId, out completionWrapper))
                    {
                        completionWrapper.Fail(new Exception(string.Format("Item {0} was not found to perform retry on ",
                                                                           correlationId)));
                    }
                }
            }
        }
        private void OnPackageReceived(Connection typedTcpConnection, TcpPackage package)
        {
            WorkItem workItem;
            ITaskCompletionWrapper wrapper;

            if (RemoveInProgressItem(package.CorrelationId, "PR", out workItem, out wrapper))
            {
            }
            else
            {
                if (!_outstandingOperations.TryGetValue(package.CorrelationId, out wrapper))
                {
                    // "SKIPPED [[ "
                    return;
                }
            }

            var result = wrapper.Process(package);
            switch (result.Status)
            {
                case ProcessResultStatus.Success:
                    wrapper.Complete();
                    break;
                case ProcessResultStatus.Retry:
                        if (wrapper.UpdateForNextAttempt())
                        {
                            RegisterHandler(wrapper.SentPackage.CorrelationId, wrapper);
                            EnqueueForSend(wrapper.SentPackage);
                        }
                        else
                            wrapper.Fail(new Exception(string.Format("Retry is not supported in wrapper {0}.", wrapper.GetType())));
                    break;
                case ProcessResultStatus.NotifyError:
                    wrapper.Fail(result.Exception);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
 internal void EnqueueForSend(TcpPackage package)
 {
     while (_sendQueue.Count > TcpSentReceiveWindow)
         Thread.Sleep(1);
     
     _sendQueue.Enqueue(package);
 }
        public Task<DeleteResult> DeleteStreamAsync(string stream, int expectedVersion)
        {
            var correlationId = Guid.NewGuid();
            var dto = new ClientMessageDto.DeleteStream(correlationId, stream, expectedVersion);

            var package = new TcpPackage(TcpCommand.DeleteStream, correlationId, dto.Serialize());
            var taskCompletionSource = new TaskCompletionSource<DeleteResult>();
            var taskWrapper = new DeleteTaskCompletionWrapper(taskCompletionSource);
            RegisterHandler(correlationId, taskWrapper);
            EnqueueForSend(package);

            return taskCompletionSource.Task;
        }
        public Task<CreateStreamResult> CreateStreamAsync(string stream, byte[] metadata)
        {
            var correlationId = Guid.NewGuid();

            var dto = new ClientMessageDto.CreateStream(correlationId,
                                                        stream,
                                                        metadata);

            var package = new TcpPackage(TcpCommand.CreateStream, correlationId, dto.Serialize());
            var taskCompletionSource = new TaskCompletionSource<CreateStreamResult>();
            var taskWrapper = new CreateStreamCompletionWrapper(taskCompletionSource);
            RegisterHandler(correlationId, taskWrapper);
            EnqueueForSend(package);

            return taskCompletionSource.Task;
        }
        public Task<WriteResult> AppendToStreamAsync(string stream, int expectedVersion, IEnumerable<Event> events)
        {
            var correlationId = Guid.NewGuid();

            var eventDtos = events.Select(x => new ClientMessageDto.Event(x.EventId,
                                                                          x.Type,
                                                                          x.Data,
                                                                          x.Metadata)).ToArray();

            var dto = new ClientMessageDto.WriteEvents(correlationId,
                                                       stream,
                                                       expectedVersion,
                                                       eventDtos);

            var package = new TcpPackage(TcpCommand.WriteEvents, correlationId, dto.Serialize());
            var taskCompletionSource = new TaskCompletionSource<WriteResult>();
            var taskWrapper = new WriteTaskCompletionWrapper(taskCompletionSource);
            RegisterHandler(correlationId, taskWrapper);
            EnqueueForSend(package);

            return taskCompletionSource.Task;
        }
        public Task<ReadResult> ReadEventStreamAsync(string stream, int start, int count)
        {
            var correlationId = Guid.NewGuid();

            var dto = new ClientMessageDto.ReadEventsFromBeginning(correlationId, stream, start, count);

            var package = new TcpPackage(TcpCommand.ReadEventsFromBeginning, correlationId, dto.Serialize());

            var taskCompletionSource = new TaskCompletionSource<ReadResult>();
            var taskWrapper = new ReadFromBeginningTaskCompletionWrapper(taskCompletionSource);
            RegisterHandler(correlationId, taskWrapper);
            EnqueueForSend(package);

            return taskCompletionSource.Task;
        }
Example #12
0
        public Connection CreateTcpConnection(Action<Connection, TcpPackage> handlePackage,
                                              Action<Connection> connectionEstablished,
                                              Action<Connection, IPEndPoint, SocketError> connectionClosed)
        {
            var connectionCreatedEvent = new AutoResetEvent(false);
            Connection typedConnection = null;

            var connection = _connector.ConnectTo(
                _tcpEndpoint,
                tcpConnection =>
                {
                    Log.Info("Connected to [{0}].", tcpConnection.EffectiveEndPoint);
                    connectionCreatedEvent.WaitOne(500);
                    connectionEstablished(typedConnection);
                },
                (conn, error) =>
                {
                    var message = string.Format("Connection to [{0}] failed. Error: {1}.", conn.EffectiveEndPoint, error);
                    Log.Error(message);

                    connectionClosed(null, conn.EffectiveEndPoint, error);
                });

            typedConnection = new Connection(connection);
            typedConnection.ConnectionClosed +=
                (conn, error) =>
                {
                    Log.Info("Connection [{0}] was closed {1}",
                             conn.EffectiveEndPoint,
                             error == SocketError.Success ? "cleanly." : "with error: " + error + ".");

                    connectionClosed(conn, conn.EffectiveEndPoint, error);
                };

            connectionCreatedEvent.Set();

            typedConnection.ReceiveAsync((conn, pkg) =>
            {
                var package = new TcpPackage();
                var valid = false;
                try
                {
                    package = TcpPackage.FromArraySegment(new ArraySegment<byte>(pkg));
                    valid = true;

                    if (package.Command == TcpCommand.HeartbeatRequestCommand)
                    {
                        var response = new TcpPackage(TcpCommand.HeartbeatResponseCommand, Guid.NewGuid(), null);
                        conn.EnqueueSend(response.AsByteArray());
                        return;
                    }

                    handlePackage(conn, package);
                }
                catch (Exception e)
                {
                    var effectiveEndPoint = conn.EffectiveEndPoint;
                    var message = string.Format("[{0}] ERROR for {1}. Connection will be closed.",
                                      effectiveEndPoint,
                                      valid ? package.Command as object : "<invalid package>");

                    Log.Info(e, message);
                    conn.Close();
                }
            });

            return typedConnection;
        }