/// <summary> /// Attempts the connection. /// </summary> /// <param name="endpoint">The endpoint.</param> /// <param name="workCategoryId">The work category identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// An awaitable task, the result is the connection result. /// </returns> protected static async Task <ConnectionResult> AttemptConnection( IPEndPoint endpoint, int workCategoryId, CancellationToken cancellationToken) { StreamWorkerConnection connection = null; try { var tcpClient = new TcpClient(); await tcpClient.ConnectAsync(endpoint.Address, endpoint.Port).ConfigureAwait(false); connection = new StreamWorkerConnection(tcpClient.GetStream()); await connection.SendIntAsync(workCategoryId, cancellationToken).ConfigureAwait(false); var benchmark = await connection.ReceiveIntAsync(cancellationToken).ConfigureAwait(false); // If we've been cancelled, trigger a clean up cancellationToken.ThrowIfCancellationRequested(); return(new ConnectionResult(connection, benchmark)); } catch (Exception ex) { if (connection != null) { connection.Dispose(); } return(new ConnectionResult(ex)); } }
/// <summary> /// Processes the client's connection and associated work item asynchronously. /// </summary> /// <param name="client">The client.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>An awaitable task.</returns> private async Task ProcessClientAsync(TcpClient client, CancellationToken cancellationToken) { IPEndPoint endpoint = null; dynamic workItem = null; try { using (var connection = new StreamWorkerConnection(client.GetStream())) { endpoint = (IPEndPoint)client.Client.RemoteEndPoint; // Get our benchmark for the provided work category var workCategoryId = await connection.ReceiveIntAsync(cancellationToken).ConfigureAwait(false); var benchmark = await _workloadBenchmark.GetScoreAsync(workCategoryId).ConfigureAwait(false); // Send the client our benchmark, they'll use this to determine whether to use us for the work await connection.SendIntAsync(benchmark, cancellationToken).ConfigureAwait(false); // Try to receive work from the client, if they close the connection then we'll catch the exception workItem = await connection.ReceiveObjectAsync(cancellationToken).ConfigureAwait(false); // do the work, capturing any exceptions that may occur object result = null; Exception exception = null; try { result = await workItem.DoWorkAsync(cancellationToken).ConfigureAwait(false); } catch (Exception ex) { exception = ex; } // Send the client the result of the work item, if an exception occurred, send that instead await connection.SendObjectAsync(exception ?? result, cancellationToken).ConfigureAwait(false); // If an exception occurred while processing work, throw it again to trigger the handling if (exception != null) { throw exception; } } } catch (Exception ex) { var message = string.Format( "An exception occurred when processing TCP client {0}:{1}.", endpoint != null ? endpoint.Address.ToString() : "????", endpoint != null ? endpoint.Port.ToString(CultureInfo.InvariantCulture) : "????"); OnWorkException(new WorkException(message, workItem, ex)); } }
/// <summary> /// Initializes a new instance of the <see cref="ConnectionResult"/> struct. /// </summary> /// <param name="connection">The connection.</param> /// <param name="benchmarkScore">The benchmark score.</param> public ConnectionResult(StreamWorkerConnection connection, int benchmarkScore) : this() { WorkerConnection = connection; CurrentWorkloadBenchmarkScore = benchmarkScore; }