{"action":"created","comment":{"url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/comments/40445974","id":40445974,"diff_hunk":"@@ -0,0 +1,156 @@\n+﻿using System;\n+using System.Collections.Concurrent;\n+using System.Collections.Generic;\n+using System.Linq;\n+using System.Threading;\n+using Druq.Framework;\n+using Druq.Framework.Database;\n+using Druq.Framework.Model;\n+using Druq.Hub;\n+using Druq.Hub.Messaging;\n+using Druq.Hub.Queuing;\n+using NUnit.Framework;\n+using SharpTestsEx;\n+\n+namespace Druq.Tests.Integration.Hub.Messaging\n+{\n+    [TestFixture]\n+    public class SkipDuplicatesServiceThreadingTests\n+    {\n+        private const string DefaultMessageKey = \"test\";\n+        private ISnapshot[] _partSnapshot;\n+        private IPartitionDb _partDb;\n+        private DateTime _now;\n+        private CurrentHub _node1CurrentHub;\n+        private CurrentHub _node2CurrentHub;\n+        private ConcurrentDictionary<string, CacheItem<RunKey>> _node1Cache;\n+        private ConcurrentDictionary<string, CacheItem<RunKey>> _node2Cache;\n+        private SkipDuplicatesService _node1Service;\n+        private SkipDuplicatesService _node2Service;\n+\n+        [TestFixtureSetUp]\n+        public void FixtureSetup()\n+        {\n+            _partDb = TestConfig.Partition1Db;\n+            _partSnapshot = Snapshot.Take(_partDb);\n+            _node1CurrentHub = new CurrentHub { Hub = TestConfig.Hub };\n+            _node2CurrentHub = new CurrentHub { Hub = IoC.Resolve<HubRegistration>().Register(\"tests-skip-dupes-node2-\" + DateTime.Now.ToString(\"yyyyMMddHHmm\")) };\n+        }\n+\n+        [TestFixtureTearDown]\n+        public void FixtureTeardown()\n+        {\n+            _partSnapshot.Restore();\n+        }\n+\n+        [SetUp]\n+        public void Setup()\n+        {\n+            _partSnapshot.Truncate();\n+            _node1Cache = new ConcurrentDictionary<string, CacheItem<RunKey>>();\n+            _node2Cache = new ConcurrentDictionary<string, CacheItem<RunKey>>();\n+            _node1Service = new SkipDuplicatesService(_node1CurrentHub, _node1Cache);\n+            _node2Service = new SkipDuplicatesService(_node2CurrentHub, _node2Cache);\n+            _now = Time.Now;\n+        }\n+\n+        [Test]\n+        public void TrySkipDupes_within_one_node_Should_process_one_at_a_time()\n+        {\n+            var bag = new ConcurrentBag<ProcessResults>();\n+            var trySkipDupes = new ThreadStart(() => bag.Add(Process(_node1Service)));\n+\n+            var threads = new List<Thread>();\n+            for (int i = 0; i < 10; i++)\n+            {\n+                threads.Add(new Thread(trySkipDupes));\n+            }\n+\n+            foreach (var thread in threads)\n+            {\n+                thread.Start();\n+            }\n+\n+            while (!threads.All(t => t.ThreadState == ThreadState.Stopped || t.ThreadState == ThreadState.Aborted))\n+            {\n+                Thread.Sleep(500);\n+            }\n+\n+            bag.Count(r => r.Processed).Should().Be(1);\n+        }\n+\n+        [Test]\n+        public void ForceSkipDupes_within_Should_process_one_at_a_time()\n+        {\n+            var bag = new ConcurrentBag<ProcessResults>();\n+            var trySkipDupes = new ThreadStart(() => bag.Add(Process(_node1Service)));\n+            var forceSkipDupes = new ThreadStart(() => bag.Add(Process(_node2Service, forceSkipDupes:true)));","path":"Druq.Tests.Integration/Hub/Messaging/SkipDuplicatesServiceThreadingTests.cs","position":87,"original_position":87,"commit_id":"c3e625e557e8233f99a455312343bb243e2a2522","original_commit_id":"c3e625e557e8233f99a455312343bb243e2a2522","user":{"login":"drewburlingame","id":103345,"avatar_url":"https://avatars.githubusercontent.com/u/103345?v=3","gravatar_id":"","url":"https://api.github.com/users/drewburlingame","html_url":"https://github.com/drewburlingame","followers_url":"https://api.github.com/users/drewburlingame/followers","following_url":"https://api.github.com/users/drewburlingame/following{/other_user}","gists_url":"https://api.github.com/users/drewburlingame/gists{/gist_id}","starred_url":"https://api.github.com/users/drewburlingame/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/drewburlingame/subscriptions","organizations_url":"https://api.github.com/users/drewburlingame/orgs","repos_url":"https://api.github.com/users/drewburlingame/repos","events_url":"https://api.github.com/users/drewburlingame/events{/privacy}","received_events_url":"https://api.github.com/users/drewburlingame/received_events","type":"User","site_admin":false},"body":"var forceSkipDupesOnNode2 = new ThreadStart(() => bag.Add(Process(_node2Service, forceSkipDupes:true)));","created_at":"2015-09-25T16:03:46Z","updated_at":"2015-09-25T16:03:46Z","html_url":"https://github.com/daptiv/Daptiv.Bus/pull/101#discussion_r40445974","pull_request_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101","_links":{"self":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/comments/40445974"},"html":{"href":"https://github.com/daptiv/Daptiv.Bus/pull/101#discussion_r40445974"},"pull_request":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101"}}},"pull_request":{"url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101","id":46017736,"html_url":"https://github.com/daptiv/Daptiv.Bus/pull/101","diff_url":"https://github.com/daptiv/Daptiv.Bus/pull/101.diff","patch_url":"https://github.com/daptiv/Daptiv.Bus/pull/101.patch","issue_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/101","number":101,"state":"open","locked":false,"title":"99050-deadlock-on-workspacedelete","user":{"login":"feliara8","id":7048028,"avatar_url":"https://avatars.githubusercontent.com/u/7048028?v=3","gravatar_id":"","url":"https://api.github.com/users/feliara8","html_url":"https://github.com/feliara8","followers_url":"https://api.github.com/users/feliara8/followers","following_url":"https://api.github.com/users/feliara8/following{/other_user}","gists_url":"https://api.github.com/users/feliara8/gists{/gist_id}","starred_url":"https://api.github.com/users/feliara8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/feliara8/subscriptions","organizations_url":"https://api.github.com/users/feliara8/orgs","repos_url":"https://api.github.com/users/feliara8/repos","events_url":"https://api.github.com/users/feliara8/events{/privacy}","received_events_url":"https://api.github.com/users/feliara8/received_events","type":"User","site_admin":false},"body":null,"created_at":"2015-09-25T14:26:57Z","updated_at":"2015-09-25T16:03:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d69d43ae9ca952e377a6544e87e0d015a40a1b64","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101/commits","review_comments_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101/comments","review_comment_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/comments{/number}","comments_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/101/comments","statuses_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/statuses/c3e625e557e8233f99a455312343bb243e2a2522","head":{"label":"daptiv:99050-deadlock-on-workspacedeletemessaeg-processing","ref":"99050-deadlock-on-workspacedeletemessaeg-processing","sha":"c3e625e557e8233f99a455312343bb243e2a2522","user":{"login":"daptiv","id":601501,"avatar_url":"https://avatars.githubusercontent.com/u/601501?v=3","gravatar_id":"","url":"https://api.github.com/users/daptiv","html_url":"https://github.com/daptiv","followers_url":"https://api.github.com/users/daptiv/followers","following_url":"https://api.github.com/users/daptiv/following{/other_user}","gists_url":"https://api.github.com/users/daptiv/gists{/gist_id}","starred_url":"https://api.github.com/users/daptiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daptiv/subscriptions","organizations_url":"https://api.github.com/users/daptiv/orgs","repos_url":"https://api.github.com/users/daptiv/repos","events_url":"https://api.github.com/users/daptiv/events{/privacy}","received_events_url":"https://api.github.com/users/daptiv/received_events","type":"Organization","site_admin":false},"repo":{"id":17488097,"name":"Daptiv.Bus","full_name":"daptiv/Daptiv.Bus","owner":{"login":"daptiv","id":601501,"avatar_url":"https://avatars.githubusercontent.com/u/601501?v=3","gravatar_id":"","url":"https://api.github.com/users/daptiv","html_url":"https://github.com/daptiv","followers_url":"https://api.github.com/users/daptiv/followers","following_url":"https://api.github.com/users/daptiv/following{/other_user}","gists_url":"https://api.github.com/users/daptiv/gists{/gist_id}","starred_url":"https://api.github.com/users/daptiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daptiv/subscriptions","organizations_url":"https://api.github.com/users/daptiv/orgs","repos_url":"https://api.github.com/users/daptiv/repos","events_url":"https://api.github.com/users/daptiv/events{/privacy}","received_events_url":"https://api.github.com/users/daptiv/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/daptiv/Daptiv.Bus","description":"Temporary message bus until we can get resources for a real message bus","fork":false,"url":"https://api.github.com/repos/daptiv/Daptiv.Bus","forks_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/forks","keys_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/teams","hooks_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/hooks","issue_events_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/events{/number}","events_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/events","assignees_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/assignees{/user}","branches_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/branches{/branch}","tags_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/tags","blobs_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/refs{/sha}","trees_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/statuses/{sha}","languages_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/languages","stargazers_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/stargazers","contributors_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/contributors","subscribers_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/subscribers","subscription_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/subscription","commits_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/commits{/sha}","git_commits_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/commits{/sha}","comments_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/comments{/number}","issue_comment_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/comments{/number}","contents_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/contents/{+path}","compare_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/merges","archive_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/downloads","issues_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues{/number}","pulls_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls{/number}","milestones_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/milestones{/number}","notifications_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/labels{/name}","releases_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/releases{/id}","created_at":"2014-03-06T18:32:04Z","updated_at":"2015-05-21T07:15:37Z","pushed_at":"2015-09-25T14:26:58Z","git_url":"git://github.com/daptiv/Daptiv.Bus.git","ssh_url":"git@github.com:daptiv/Daptiv.Bus.git","clone_url":"https://github.com/daptiv/Daptiv.Bus.git","svn_url":"https://github.com/daptiv/Daptiv.Bus","homepage":null,"size":14672,"stargazers_count":2,"watchers_count":2,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":5,"forks":0,"open_issues":5,"watchers":2,"default_branch":"master"}},"base":{"label":"daptiv:master","ref":"master","sha":"42f19d9a8dad8392cfe8677505d34e4657f5c669","user":{"login":"daptiv","id":601501,"avatar_url":"https://avatars.githubusercontent.com/u/601501?v=3","gravatar_id":"","url":"https://api.github.com/users/daptiv","html_url":"https://github.com/daptiv","followers_url":"https://api.github.com/users/daptiv/followers","following_url":"https://api.github.com/users/daptiv/following{/other_user}","gists_url":"https://api.github.com/users/daptiv/gists{/gist_id}","starred_url":"https://api.github.com/users/daptiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daptiv/subscriptions","organizations_url":"https://api.github.com/users/daptiv/orgs","repos_url":"https://api.github.com/users/daptiv/repos","events_url":"https://api.github.com/users/daptiv/events{/privacy}","received_events_url":"https://api.github.com/users/daptiv/received_events","type":"Organization","site_admin":false},"repo":{"id":17488097,"name":"Daptiv.Bus","full_name":"daptiv/Daptiv.Bus","owner":{"login":"daptiv","id":601501,"avatar_url":"https://avatars.githubusercontent.com/u/601501?v=3","gravatar_id":"","url":"https://api.github.com/users/daptiv","html_url":"https://github.com/daptiv","followers_url":"https://api.github.com/users/daptiv/followers","following_url":"https://api.github.com/users/daptiv/following{/other_user}","gists_url":"https://api.github.com/users/daptiv/gists{/gist_id}","starred_url":"https://api.github.com/users/daptiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daptiv/subscriptions","organizations_url":"https://api.github.com/users/daptiv/orgs","repos_url":"https://api.github.com/users/daptiv/repos","events_url":"https://api.github.com/users/daptiv/events{/privacy}","received_events_url":"https://api.github.com/users/daptiv/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/daptiv/Daptiv.Bus","description":"Temporary message bus until we can get resources for a real message bus","fork":false,"url":"https://api.github.com/repos/daptiv/Daptiv.Bus","forks_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/forks","keys_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/teams","hooks_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/hooks","issue_events_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/events{/number}","events_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/events","assignees_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/assignees{/user}","branches_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/branches{/branch}","tags_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/tags","blobs_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/refs{/sha}","trees_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/statuses/{sha}","languages_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/languages","stargazers_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/stargazers","contributors_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/contributors","subscribers_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/subscribers","subscription_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/subscription","commits_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/commits{/sha}","git_commits_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/git/commits{/sha}","comments_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/comments{/number}","issue_comment_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/comments{/number}","contents_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/contents/{+path}","compare_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/merges","archive_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/downloads","issues_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues{/number}","pulls_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls{/number}","milestones_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/milestones{/number}","notifications_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/labels{/name}","releases_url":"https://api.github.com/repos/daptiv/Daptiv.Bus/releases{/id}","created_at":"2014-03-06T18:32:04Z","updated_at":"2015-05-21T07:15:37Z","pushed_at":"2015-09-25T14:26:58Z","git_url":"git://github.com/daptiv/Daptiv.Bus.git","ssh_url":"git@github.com:daptiv/Daptiv.Bus.git","clone_url":"https://github.com/daptiv/Daptiv.Bus.git","svn_url":"https://github.com/daptiv/Daptiv.Bus","homepage":null,"size":14672,"stargazers_count":2,"watchers_count":2,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":5,"forks":0,"open_issues":5,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101"},"html":{"href":"https://github.com/daptiv/Daptiv.Bus/pull/101"},"issue":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/101"},"comments":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/issues/101/comments"},"review_comments":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101/comments"},"review_comment":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/pulls/101/commits"},"statuses":{"href":"https://api.github.com/repos/daptiv/Daptiv.Bus/statuses/c3e625e557e8233f99a455312343bb243e2a2522"}}}}