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; }
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; }