Embedio: CancellationToken takes too long to cancel server task

Created on 21 Dec 2017  路  17Comments  路  Source: unosquare/embedio

frontendTask.ContinueWith(result =>
    {
        OnPropertyChanged("FrontendLabel");
        OnPropertyChanged("ToggleFrontend");
        frontendServer.Dispose();
    });

the frontendCancellor.Cancel(); take a couple of minutes to complete.

bug help wanted

Most helpful comment

I think I hit the same problem.. Trying to cancel server task takes forever, but happens immediately, if I visit the webservers address after cancel. My code looks like following:

System.Diagnostics.Debug.WriteLine("::1::");
serverToken.Cancel();
System.Diagnostics.Debug.WriteLine("::2::");
serverTask.Wait();
System.Diagnostics.Debug.WriteLine("::3::");

In console, I get the ::1:: and ::2:: lines, but ::3:: appears only after a long delay, or after visiting the servers address with browser. I think that the problem lies in this code:

https://github.com/unosquare/embedio/blob/master/src/Unosquare.Labs.EmbedIO/WebServer.cs

lines 331-333 ..

var clientSocket = await Listener.GetContextAsync().ConfigureAwait(false);
if (ct.IsCancellationRequested)
  return;

If I understand this correctly the lister needs a new connection or timeout to continue to the cancel part of the loop. Which causes at least the issues I'm having

All 17 comments

What is frontendCancellor? Can you explain a little more?

Sorry for the confusion.

        private void __StartFrontend(object obj)
        {
            if (!Directory.Exists(FrontendRoot))
            {
                MessageBox.Show("frontend folder is missing.");
                return;
            }
            var url = "http://localhost:8080/";
            frontendServer = new WebServer(url);
            frontendServer.RegisterModule(new StaticFilesModule(FrontendRoot));
            frontendServer.Module<StaticFilesModule>().UseRamCache = true;
            frontendServer.Module<StaticFilesModule>().DefaultExtension = ".html";
            // We don't need to add the line below. The default document is always index.html.
            //server.Module<Modules.StaticFilesWebModule>().DefaultDocument = "index.html";
            frontendCancellor = new CancellationTokenSource();
            frontendTask = frontendServer.RunAsync(frontendCancellor.Token);
            OnPropertyChanged("FrontendLabel");
            OnPropertyChanged("ToggleFrontend");
        }
        public void __StopFrontend(object obj)
        {
            frontendCancellor.Cancel();
            frontendTask.Wait();
            OnPropertyChanged("FrontendLabel");
            OnPropertyChanged("ToggleFrontend");
        }

Is the cancellation meant to be taking a while?

@hardywu what runtime are you using? .NET 46?

Yes.

I think I hit the same problem.. Trying to cancel server task takes forever, but happens immediately, if I visit the webservers address after cancel. My code looks like following:

System.Diagnostics.Debug.WriteLine("::1::");
serverToken.Cancel();
System.Diagnostics.Debug.WriteLine("::2::");
serverTask.Wait();
System.Diagnostics.Debug.WriteLine("::3::");

In console, I get the ::1:: and ::2:: lines, but ::3:: appears only after a long delay, or after visiting the servers address with browser. I think that the problem lies in this code:

https://github.com/unosquare/embedio/blob/master/src/Unosquare.Labs.EmbedIO/WebServer.cs

lines 331-333 ..

var clientSocket = await Listener.GetContextAsync().ConfigureAwait(false);
if (ct.IsCancellationRequested)
  return;

If I understand this correctly the lister needs a new connection or timeout to continue to the cancel part of the loop. Which causes at least the issues I'm having

@McFizh can you test using the branch Issue121-CancellationDelay?

This new branch fixed my issue.. Thanks :)

Edit: although , just canceling task doesn't release the tcp port. I need to also call dispose method, but that in turn emits ObjectDisposedException

@hardywu can you verify?

@McFizh can you post a sample code?

@McFizh I was able to reproduce the issue, I committed some changes to stop the Listener.

With the latest changes the tcp port gets properly released and I can create/close server in a loop without problems. But with code shown below:

server = new WebServer("http://localhost:8080/", Unosquare.Labs.EmbedIO.Constants.RoutingStrategy.Regex);

serverToken = new CancellationTokenSource();
serverTask = server.RunAsync(serverToken.Token);

..............

System.Diagnostics.Debug.WriteLine("!1!");
serverToken.Cancel();
System.Diagnostics.Debug.WriteLine("!2!");
serverTask.Wait();
System.Diagnostics.Debug.WriteLine("!3!");

I get output like this:

!1!
!2!
Exception thrown: 'System.ObjectDisposedException' in System.dll
!3!

Edit.. I removed module from code example, as it didn't seem to have any effect

Do you have the stacktrace?

[External Code]
Unosquare.Labs.EmbedIO.dll!Unosquare.Net.EndPointListener.Accept(System.Net.Sockets.Socket socket, System.Net.Sockets.SocketAsyncEventArgs e, ref System.Net.Sockets.Socket accepted) Line 238
Unosquare.Labs.EmbedIO.dll!Unosquare.Net.EndPointListener.ProcessAccept(System.Net.Sockets.SocketAsyncEventArgs args) Line 270
Unosquare.Labs.EmbedIO.dll!Unosquare.Net.EndPointListener.OnAccept(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 292
[External Code]

And the error itself is:

System.ObjectDisposedException
HResult=0x80131622
Message=Ei voi k盲ytt盲盲 poistettua objektia (translation: unable to used removed object).
Objektin nimi (translation: object name): System.Net.Sockets.Socket.
Source=System
StackTrace:
at System.Net.Sockets.Socket.AcceptAsync(SocketAsyncEventArgs e)
at Unosquare.Net.EndPointListener.Accept(Socket socket, SocketAsyncEventArgs e, Socket& accepted) in C:\Users\xyz\Source\Workspaces\embedio\src\Unosquare.Labs.EmbedIO\System.Net\EndPointListener.cs:line 238

My results:

The thread 0x96c4 has exited with code 0 (0x0).
!1!
!2!
!3!
Exception thrown: 'System.ObjectDisposedException' in System.dll
Exception thrown: 'System.ObjectDisposedException' in System.dll

But I'm not getting any exception to handle with Visual Studio. I think this is somehow expected because the EndPoint is shutting down and the socket is disposed.

I added "Unosquare.Labs.EmbedIO" project as a dependency solution to my project, and had to explicitly enable ObjectDisposedException exceptions in visual studio 2017 (it was disabled as default and hidden in submenus).

Oh and some times I also had the exception pop up after marker !3! .. might have something to do with threading (?) , but anyways the exception always happens at the same line

Yeah, but I don't see any practical solution here. Even if I catch ObjectDisposedException in Unosquare.Net.EndPointListener.Accept, the exception was raised and reported.

Any idea?

@McFizh ??

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RyanYANG52 picture RyanYANG52  路  4Comments

rdeago picture rdeago  路  6Comments

simohr picture simohr  路  5Comments

geoperez picture geoperez  路  8Comments

chyyran picture chyyran  路  6Comments