1

I have a simple console app which waits for incoming connections and then pipes/tunnels any incoming connection to a local service which is bound to the loopback interfaces.

The methods which perform this tunneling are async and long running - they will only terminate when the internal service stops or the client disconnect (which can be hours in duration). Currently this works but I am uncertain if the approach is correct as I do not "await" on the long running operations. I'm curious what is the proper way to handle this?

The compiler actually complains: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

public async Task Start(CancellationToken ct)
{
    _socket.Bind(_portMapping.Source);
    _socket.Listen(MaxQueuedConnections);
    var args = new SocketAsyncEventArgs();
    var awaitable = new SocketAwaitable(args);

    while (!ct.IsCancellationRequested)
    {
        args.AcceptSocket = null;
        await _socket.AcceptAsync(awaitable);
        var listenerSource = args.AcceptSocket;

        var feed = new MyForwarder(_portMapping.Remote.Address, 
                                   _portMapping.Remote.Port, MaxRetries);
        feed.Connect();
        if (feed.Socket.Connected && listenerSource != null && listenerSource.Connected)
        {
            // Both calls are async and long running.  How should I handle as I want
            // to continue to listen for an incoming connection 
            feed.Pipe(listenerSource, ct);
            ForwardHelper.Pipe(listenerSource, feed.Socket, ct);
        }
    }
}
Dave
  • 2,386
  • 1
  • 20
  • 38
  • Looks ok (as long as you don't shut down your process as soon as task started). You can replace `Task` with `void` to remove warning (bad idea, but...). Otherwise fire-and-forget is discussed in http://stackoverflow.com/questions/12803012/fire-and-forget-with-async-vs-old-async-delegate. – Alexei Levenkov Sep 22 '15 at 20:01
  • Your task doesn't need to be awaited on, but is it fine if it stopped/crashed and you don't know about it? – displayName Sep 22 '15 at 20:23

1 Answers1

3

That's correct as it is. Since you do not want to wait there is no need to await.

Make sure that you handle all errors. Dropped exceptions make it hard to debug. For example, you could do:

Task.WhenAll(a, b).ContinueWith(_ => /* handle errors */);

Any other way to handle errors would also work.

usr
  • 168,620
  • 35
  • 240
  • 369
  • Worth mentioning that prior to .NET 4.5, failure to *observe* an unhandled exception from a Task crashes the process. More info here: http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/task-exception-handling-in-net-4-5.aspx – sstan Sep 22 '15 at 20:27
  • Still wrapping my head around exception handling with Tasks. In most cases should the errors be handled at lowest level within the task or should they be allowed to flow up as aggregate exceptions? Also, is there any need to use Task.Run or Task.Factory.StartNew – Dave Sep 22 '15 at 20:40
  • They should be handled at the right architectural level. For example if you want to show a GUI message you probably want to handle the exception as far outside as possible. Exception handling architecture with tasks is not different than with threads or other control flow. – usr Sep 22 '15 at 21:55
  • "is there any need...Run" that's a long story that you probably should search for... Here, I have seen no indication that this might be necessary. – usr Sep 22 '15 at 21:56