Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failing Local Session Module because of KeyNotFoundException #56

Closed
harper10 opened this issue Dec 14, 2016 · 19 comments
Closed

Failing Local Session Module because of KeyNotFoundException #56

harper10 opened this issue Dec 14, 2016 · 19 comments
Assignees

Comments

@harper10
Copy link

I keep seeing the following error.

Failing module name: Local Session Module
The given key was not present in the dictionary.

Stack Trace:

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].get_Item (System.Collections.Concurrent.TKey key) in /private/tmp/source-mono-mac-4.2.0-branch/bockbuild-mono-4.2.0-pre2-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.0/external/referencesource/mscorlib/system/collections/Concurrent/ConcurrentDictionary.cs:line 955
   at Unosquare.Labs.EmbedIO.Modules.LocalSessionModule.<.ctor>b__4_0 (Unosquare.Labs.EmbedIO.WebServer server, System.Net.HttpListenerContext context) in <filename unknown>:line 0
   at Unosquare.Labs.EmbedIO.WebServer.ProcessRequest (System.Net.HttpListenerContext context) in <filename unknown>:line 0
@geoperez geoperez self-assigned this Dec 14, 2016
@geoperez
Copy link
Member

Hi @harper10, can you help me with a snippet of your code?

@harper10
Copy link
Author

What code are you looking for? The error happens intermittently, and it recently started happening more recently. Most of the requests are served normally. I think the error is in the LocalSessionModules.cs file where the ConcurrentDictionary is being used to get items from the dictionary.

@mariodivece
Copy link
Member

mariodivece commented Dec 14, 2016 via email

@harper10
Copy link
Author

I think the problem here is that when Sessions[key] is called, key is not guaranteed to be in the concurrentDictionary.

var allKeys = Sessions.Keys.ToArray();
foreach (var key in allKeys)
{
    var sessionInfo = Sessions[key];
    if (DateTime.Now.Subtract(sessionInfo.LastActivity) > Expiration)
         Sessions.TryRemove(key, out sessionInfo);
}

The key could have been removed by another thread. Instead

var allKeys = Sessions.Keys.ToArray();
foreach (var key in allKeys)
{
    SessionInfo sessionInfo;
    if (Sessions.TryGetValue(key, out sessionInfo))
    {
        if (DateTime.Now.Subtract(sessionInfo.LastActivity) > Expiration)
            Sessions.TryRemove(key, out sessionInfo);
    }
}

will make sure that the key is still in the dictionary.

@geoperez
Copy link
Member

@harper10 I just updated the nuget (1.2.5) with your suggestion. Let me know if it works for you now.

@harper10
Copy link
Author

I haven't been able to test it because I am getting the same error referenced in #57

@geoperez
Copy link
Member

Can you try again?

@harper10
Copy link
Author

The error has changed to
'EmbedIO' already has a dependency defined for 'System.Collections.Specialized'

@geoperez
Copy link
Member

Can you paste your project.json?

@mariodivece
Copy link
Member

@harper10 sometimes I have found that restarting Visual Studio and reopening the solution helps. Xproj projects seems to still be somewhat buggy when it comes to dependencies. Please paste your project.json file here and try my solution also.

@harper10
Copy link
Author

I was able to use the updated nuget client, and I got a different error.

Could not install package 'EmbedIO 1.2.7'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5', but the package does not contain any assembly references or content files that are compatible with that framework.

Unfortunately I cannot switch from .Net Version 4.5 because my project is using mono. Are there anyway plans for mono to be supported with the new package?

@geoperez
Copy link
Member

You can use NET452 with MONO, I think you only need to use the TargetFrameworkVersion=v4.5 parameter. We use it on Travis to build EmbedIO in Mono.

xbuild Unosquare.Labs.EmbedIO.Lib.sln /p:"TargetFrameworkVersion=v4.5;Configuration=Release"

@bufferUnderrun
Copy link
Contributor

@geoperez i've updated to the last v1.2.8 package and still have this issue.

@geoperez
Copy link
Member

geoperez commented Jan 4, 2017

Let me take a look

@geoperez
Copy link
Member

geoperez commented Jan 5, 2017

I'm getting another error:

Collection was modified; enumeration operation may not execute.

With the following code:

var webServerUrl = "http://localhost:9090";

            var webServer = new WebServer(webServerUrl);
            webServer.RegisterModule(new LocalSessionModule() { Expiration = TimeSpan.FromSeconds(6) });
            webServer.RegisterModule(new FallbackModule((ws, ctx) =>
            {
                return ctx.JsonResponse(new { Message = "OK" });
            }));

            webServer.RunAsync();

            var rnd = new Random();

            Parallel.ForEach(Enumerable.Range(0, 50), async (s, t, l) =>
            {
                await Task.Delay(TimeSpan.FromSeconds(rnd.Next(1, 10)));

                using (var webClient = new HttpClient())
                {
                    var data = await webClient.GetStringAsync(webServerUrl);
                    data.Info();
                }
            });

            Console.ReadKey();

The error it's because the collection change when you delete a session. So I change to create a new collection only for iteration at LocalSessionModule:

var currentSessions = new Dictionary<string, SessionInfo>(m_Sessions);

                    // expire old sessions
                    foreach (var session in currentSessions)
                    {
                        if (session.Value == null) continue;

                        if (DateTime.Now.Subtract(session.Value.LastActivity) > Expiration)
                            DeleteSession(session.Value);
                    }

I'll publish this change at version 1.4.2.

geoperez added a commit that referenced this issue Jan 5, 2017
@bufferUnderrun
Copy link
Contributor

I thought that the lock(SessionsSyncLock) forced threads to sync ? So it does not work this way ?
I will test it

@mariodivece
Copy link
Member

It should @bufferUnderrun the lock statement creates a critical section in which no more than 1 thread can enter.

@geoperez
Copy link
Member

geoperez commented Jan 9, 2017

@bufferUnderrun did you test the new version?

@bufferUnderrun
Copy link
Contributor

@geoperez yes, test 1 day and run in prod for 2 days. You can close the issue. Thanks for you fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants