{"action":"created","comment":{"url":"https://api.github.com/repos/Particular/docs.particular.net/pulls/comments/85858242","pull_request_review_id":6548573,"id":85858242,"diff_hunk":"@@ -0,0 +1,195 @@\n+---\n+title: \"NServiceBus 101 Lesson 5: Retrying errors\"\n+---\n+\n+In software systems, exceptions are a fact of life. Even with perfect, bug-free code, problems will arise when we have to deal with the issue of connectivity. If a database is overloaded, or a web service is down, we have no recourse except to try again.\n+\n+It's how we respond to exceptions that is important. When a database is deadlocked, or a web service is down, do we lose data, or do we have the ability to recover? Do our users get an error message and have to figure out how to recover on their own, or can we make it appear as though nothing ever went wrong?\n+\n+\n+## Objectives\n+\n+By the end of this lesson, you will have learned:\n+\n+ * The different causes of exceptions, and how to deal with them\n+ * How to use immediate retries to resolve transient errors\n+ * How to use delayed retries to resolve semi-transient errors\n+ * How to use message replay to resolve systemic errors\n+\n+\n+## Causes of errors\n+\n+In systems programming, where connectivity is a major concern, there are generally three broad categories of exceptions:\n+\n+\n+### Transient exceptions\n+\n+Transient exceptions are those that, if immediately retried, would likely succeed.\n+\n+Let's consider a common scenario. You have some code that updates a record in the database. Two threads attempt to lock the row at the same time, resulting in a deadlock. The database chooses one transaction to succeed and the other fails. The exception message Microsoft SQL Server returns for a deadlock is this:\n+\n+WARNING: Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.\n+\n+This is an example of a **transient exception**. Transient exceptions appear to be caused by random quantum fluctuations in the ether. If the failing code is immediately retried, it will probably succeed. Indeed, the exception message above tells us to do exactly that.\n+\n+\n+### Semi-transient exceptions\n+\n+The next category involves failures such as connecting to a web service that goes down intermittently. An immediate retry will likely not succeed, but retrying after a short time (from a few seconds up to a few minutes) might.\n+\n+These are **semi-transient exceptions**. Semi-transient exceptions are persistent for a limited time but still resolve themselves relatively quickly.\n+\n+Another common example involves the failover of a database cluster. If a database has enough pending transactions, it can take a minute or two for all of those transactions to resolve before the failover can complete. During this time, queries are executed without issue, but attempting to modify data will result in an exception.\n+\n+It can be difficult to deal with this type of failure, as it's frequently not possible for the calling thread to wait around long enough for the failure to resolve.\n+\n+\n+### Systemic exceptions\n+\n+Outright flaws in your system cause **systemic exceptions**, which are straight-up bugs. They will fail every time given the same input data. These are our good friends NullReferenceException, ArgumentException, dividing by zero, and a host of other common mistakes we've all made.\n+\n+In short, these are the exceptions that a developer needs to look at, triage, and fix—preferably without all the noise from the transient and semi-transient getting in the way of our investigation.\n+\n+\n+## Automatic retries\n+\n+In order to deal with exceptions that arise within message handlers, NServiceBus wraps each message handler in a `try/catch` block, and if the message transport supports it, a transaction as well. This means that only one of two things can happen:\n+\n+ 1. The message is processed successfully. All database calls succeed, all outgoing messages are dispatched to the message transport, and the incoming message is removed from the queue.\n+ 1. The message fails. All database transactions are rolled back, any calls to `.Send()` or `.Publish()` are cancelled, and the incoming message remains in the queue to attempt processing again.\n+\n+With this kind of protection in place, we're free to try to process a message as many times as we need, or at least as many times as makes sense.\n+\n+**Immediate retries** deal with transient exceptions like deadlocks. By default, messages will be immediately retried up to 5 times. If a handler method continues to throw an exception after 5 consecutive attempts, it is clearly not a transient exception.\n+\n+**Delayed retries** deal with semi-transient exceptions, like a flaky web service, or database failover. It uses a series of successively longer delays between retries in order to give the failing resource some breathing room. After immediate retries are exhausted, the message is moved aside for a short time – 10 seconds by default – and then another set of retries is attempted. If this fails, the time limit is increased and then the message handler will try again.\n+\n+All told, with default settings, delayed retries will attempt 4 rounds of immediate retries with delays increasing by 10 seconds for each round, resulting in 20 processing attempts in total:\n+\n+ 1. 5 processing attempts, followed by 10 second delay\n+ 1. 5 processing attempts, followed by 20 second delay\n+ 1. 5 processing attempts, followed by 30 second delay\n+ 1. 5 processing attempts, then the message is moved to the error queue\n+\n+The last step, moving the message to an error queue, is how NServiceBus deals with **systemic exceptions**. In a messaging system, systemic exceptions are the cause of **poison messages**, messages that cannot be processed successfully under any circumstances. Poison messages have to be moved aside, otherwise they will clog up the queue and prevent valid messages from being processed.\n+\n+We'll take a look at a few options for configuring retries in the exercise, but for all the details check out the [recoverability documentation](/nservicebus/recoverability/).\n+\n+\n+## Replaying messages\n+\n+Once a message is sent to the error queue, this indicates that a systemic failure has occurred. When this happens, a developer needs to look at the message and figure out *why*.\n+\n+For this reason, NServiceBus embeds the exception details and stack trace into the message that it forwards to the error queue, so you don't even need to search through a log file to find the details – everything you need is right there! Once the underlying issue is fixed, the message can be replayed. **Replaying a message** sends it back to its original queue in order to retry message processing after an issue has been fixed.\n+\n+NServiceBus comes with tools to make this kind of operational monitoring really easy. If you installed the rest of the [Particular Service Platform](http://particular.net/downloads), you already have these at your disposal:\n+\n+ * [ServiceControl](/servicecontrol/) is like a brain monitoring your systems, sucking in information and making that available to other tools via a REST API. One of its functions is to monitor your error queue so that you can act on the poison messages that arrive there.\n+ * [ServicePulse](/servicepulse/) is a web application aimed to be an operational dashboard for your NServiceBus system. It allows you to see failed messages, including the exception details, and provides a UI to either replay or archive failed messages.\n+\n+Sometimes, a new release will contain a bug in handler logic that isn't found until the code is deployed. When this happens, many errors can flood into the error queue at once. At these times, it's incredibly valuable to be able to rollback to the old version of the endpoint, and then replay the messages through proven code. Then you can take the time to properly troubleshoot and fix the issue before attempting a new deployment.\n+\n+\n+## Exercise\n+\n+This is an exploratory exercise, where we'll be playing with different retry options. We'll use the [completed solution from the previous lesson](https://github.com/Particular/docs.particular.net/tree/academy-nsb101/tutorials/nservicebus-101/lesson-4/solution/).\n+\n+\n+### Throw an exception\n+\n+For the purposes of this exercise, we'll create a specific bug in the Sales endpoint and watch what happens when we run the endpoint.\n+\n+1. In the **Sales** endpoint, locate the **PlaceOrderHandler**.\n+2. After logging receipt of the message, throw an exception:\n+\n+snippet:Throw\n+\n+Now, run the solution.\n+\n+ 1. In Visual Studio's **Debug** menu, select **Detach All** so that the system keeps running, but does not break into the debugger when we throw our exception.\n+ 1. In the **ClientUI** window, place an order by pressing `P`, and then watch carefully!\n+\n+When we do these steps, we'll see a wall of exception messages in white text, which is log level INFO, followed by one in yellow text, which is log level WARN. The exception traces in white are the failures during immediate retries, and the last trace in yellow is the failure that hands the message over to delayed retries.\n+\n+```no-highlight\n+INFO  Sales.PlaceOrderHandler Received PlaceOrder, OrderId = e927667c-b949-47ee-8ea2-f29523909784\n+WARN  NServiceBus.RecoverabilityExecutor Delayed Retry will reschedule message '53ac6836-48ef-49dd-aabb-a67c0104a2a5' after a delay of 00:00:10 because of an exception:\n+System.Exception: BOOM!\n+   at <stack trace>\n+```\n+\n+10 seconds later, the retries begin again, followed by another yellow trace, sending the message back to delayed retries. 20 seconds after that, another set of traces. Finally, 30 seconds after that, the final exception trace will be shown in red, which is log level ERROR. This is where NServiceBus gives up on the message and redirects it to the error queue.\n+\n+```no-highlight\n+INFO  Sales.PlaceOrderHandler Received PlaceOrder, OrderId = e927667c-b949-47ee-8ea2-f29523909784\n+ERROR NServiceBus.RecoverabilityExecutor Moving message '53ac6836-48ef-49dd-aabb-a67c0104a2a5' to the error queue 'error' because processing failed due to an exception:\n+System.Exception: BOOM!\n+   at < stack trace>\n+```\n+\n+\n+### Modify immediate retries\n+\n+The only configurable option you need for immediate retries is how many of them to attempt. The default value is `5`, but you may want to set it to a higher or lower number. Many developers prefer to set it to `0` so that they can avoid the \"wall of text\" effect when an exception is thrown during development, and then set it to a higher number for production use.\n+\n+ 1. In the **Sales** endpoint, locate the **Program.cs** file.\n+ 1. Before the endpoint is started, add the following code:\n+\n+snippet:ImmediateRetries\n+\n+Now, re-run the solution.\n+\n+Notice how delayed retries still occur (with exception traces in yellow) but no immediate retries (in white) occur between each delayed retry.\n+\n+Of course, the number of retries supplied to the immediate retries API can be pulled from an appSetting to allow changing configuration between development/test/staging/production environments.\n+\n+\n+### Modify delayed retries\n+\n+Now let's try modifying the delayed retries. First let's try disabling them completely, which can also be beneficial during development to remove noise.\n+\n+Modify the recoverability code you wrote previously, then re-run the solution:\n+\n+snippet:DelayedRetries\n+\n+Notice how the message is only attempted once. The stack trace is red, and the message is immediately forwarded to the error queue.\n+\n+With delayed retries, we can also modify the time increase applied to each round of retries. Let's reset the number of delayed retries back to `3`, and decrease the time increase to 3 seconds so the delayed retries will occur very quickly.\n+\n+Modify the same recoverability code, and re-run the solution:\n+\n+snippet:TimeIncrease\n+\n+Notice how much faster the message proceeds through delayed retries, because instead of delays of 10/20/30 seconds (60 seconds total) the delays are now 3/6/9 seconds, for a total of 18 seconds wait time.\n+\n+\n+### Replay a message\n+\n+If you used the [Particular Platform Installer](/platform/installer/) to install MSMQ, you should already have the [ServiceControl](/servicecontrol/) and [ServicePulse](/servicepulse/) tools installed.\n+\n+To check for these tools:\n+\n+ * Load the ServiceControl API at [http://localhost:33333/api](http://localhost:33333/api). If a JSON response is returned, ServiceControl is running.\n+ * Load the ServicePulse application at [http://localhost:9090/](http://localhost:9090/). If a web application is displayed, ServicePulse is running.\n+ * If either tool is not installed, [reinstall the Particular Service Platform](/platform/installer/).\n+\n+Once these tools are installed and running, you can attempt to replay a message:\n+\n+ 1. Fix the **Sales** endpoint by removing the `throw` statement.\n+ 1. Run the solution.\n+ 1. Open [ServicePulse](http://localhost:9090/) and navigate to the **Failed Messages** page. Note how similar messages are grouped together for easier handling.\n+    ![Failed Message Groups](failed-message-groups.png)\n+ 1. Click the **View Messages** link to see details on each failed message.\n+    ![Failed Message Details](failed-message-details.png)\n+ 1. Try the various methods of replaying messages and watch what happens in the console windows. Note that ServiceControl executes message retry batches on a 30-second timer, so *be patient!* Eventually, the messages will be returned to their appropriate endpoints.\n+\n+When the message is replayed in Sales, each endpoint picks up right where it left off. You should be able to see how useful this capability will be when failures happen in your real-life systems.\n+\n+\n+## Summary\n+\n+In this lesson, we explored different causes for exceptions and how NServiceBus makes those much easier to deal with by introducing automatic retries and message replay to make many transient and semi-transient exceptions just go away, and provide tools to deal with poison messages, all without our users noticing anything but perhaps a slight processing delay. This is a capability that will enable you to create truly resilient, self-healing systems that can keep running in the face of partial failure.\n+\n+Congratulations! You've completed the last lesson in NServiceBus 101: Messaging Basics. You may have noticed in this course there was a lot of code duplication. We also ignored some messaging best practices in the name of keeping the examples simple. In the next course, we'll explore how you would use NServiceBus in a real-life system. We'll remove the code duplication and make everything more [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), discuss best practices for creating and managing large NServiceBus systems, delve into web applications, and more.","path":"tutorials/nservicebus-101/lesson-5/tutorial.md","position":193,"original_position":193,"commit_id":"12aa546e8652e632136333a38251ecfdd855ed45","original_commit_id":"12aa546e8652e632136333a38251ecfdd855ed45","user":{"login":"SimonCropp","id":122666,"avatar_url":"https://avatars.githubusercontent.com/u/122666?v=3","gravatar_id":"","url":"https://api.github.com/users/SimonCropp","html_url":"https://github.com/SimonCropp","followers_url":"https://api.github.com/users/SimonCropp/followers","following_url":"https://api.github.com/users/SimonCropp/following{/other_user}","gists_url":"https://api.github.com/users/SimonCropp/gists{/gist_id}","starred_url":"https://api.github.com/users/SimonCropp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SimonCropp/subscriptions","organizations_url":"https://api.github.com/users/SimonCropp/orgs","repos_url":"https://api.github.com/users/SimonCropp/repos","events_url":"https://api.github.com/users/SimonCropp/events{/privacy}","received_events_url":"https://api.github.com/users/SimonCropp/received_events","type":"User","site_admin":false},"body":">In the next course\r\n\r\nlink to the course","created_at":"2016-11-01T00:10:09Z","updated_at":"2016-11-01T00:10:09Z","html_url":"https://github.com/Particular/docs.particular.net/pull/2114#discussion_r85858242","pull_request_url":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114","_links":{"self":{"href":"https://api.github.com/repos/Particular/docs.particular.net/pulls/comments/85858242"},"html":{"href":"https://github.com/Particular/docs.particular.net/pull/2114#discussion_r85858242"},"pull_request":{"href":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114"}}},"pull_request":{"url":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114","id":90824828,"html_url":"https://github.com/Particular/docs.particular.net/pull/2114","diff_url":"https://github.com/Particular/docs.particular.net/pull/2114.diff","patch_url":"https://github.com/Particular/docs.particular.net/pull/2114.patch","issue_url":"https://api.github.com/repos/Particular/docs.particular.net/issues/2114","number":2114,"state":"open","locked":false,"title":"NSB101 Tutorial Content (with changes for tutorial renderer)","user":{"login":"DavidBoike","id":427110,"avatar_url":"https://avatars.githubusercontent.com/u/427110?v=3","gravatar_id":"","url":"https://api.github.com/users/DavidBoike","html_url":"https://github.com/DavidBoike","followers_url":"https://api.github.com/users/DavidBoike/followers","following_url":"https://api.github.com/users/DavidBoike/following{/other_user}","gists_url":"https://api.github.com/users/DavidBoike/gists{/gist_id}","starred_url":"https://api.github.com/users/DavidBoike/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DavidBoike/subscriptions","organizations_url":"https://api.github.com/users/DavidBoike/orgs","repos_url":"https://api.github.com/users/DavidBoike/repos","events_url":"https://api.github.com/users/DavidBoike/events{/privacy}","received_events_url":"https://api.github.com/users/DavidBoike/received_events","type":"User","site_admin":false},"body":"Replaces #1905 \n\nDepends upon deployment of https://github.com/Particular/DocsEngine/pull/257 before [WIP] can be removed.\n- Tutorials identified as a tutorial.md document.\n- Tutorials have solution directories `Core_6` and snippets directory in `Snippets` and can pull snippets from both locations.\n- Completed diagrams\n- Updates from external reviews on the previous PR\n\n@SimonCropp \n","created_at":"2016-10-25T14:54:59Z","updated_at":"2016-11-01T00:10:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d083ddbe9bb671c80b5909d7a3d89814ca60f56b","assignee":{"login":"DavidBoike","id":427110,"avatar_url":"https://avatars.githubusercontent.com/u/427110?v=3","gravatar_id":"","url":"https://api.github.com/users/DavidBoike","html_url":"https://github.com/DavidBoike","followers_url":"https://api.github.com/users/DavidBoike/followers","following_url":"https://api.github.com/users/DavidBoike/following{/other_user}","gists_url":"https://api.github.com/users/DavidBoike/gists{/gist_id}","starred_url":"https://api.github.com/users/DavidBoike/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DavidBoike/subscriptions","organizations_url":"https://api.github.com/users/DavidBoike/orgs","repos_url":"https://api.github.com/users/DavidBoike/repos","events_url":"https://api.github.com/users/DavidBoike/events{/privacy}","received_events_url":"https://api.github.com/users/DavidBoike/received_events","type":"User","site_admin":false},"assignees":[{"login":"DavidBoike","id":427110,"avatar_url":"https://avatars.githubusercontent.com/u/427110?v=3","gravatar_id":"","url":"https://api.github.com/users/DavidBoike","html_url":"https://github.com/DavidBoike","followers_url":"https://api.github.com/users/DavidBoike/followers","following_url":"https://api.github.com/users/DavidBoike/following{/other_user}","gists_url":"https://api.github.com/users/DavidBoike/gists{/gist_id}","starred_url":"https://api.github.com/users/DavidBoike/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DavidBoike/subscriptions","organizations_url":"https://api.github.com/users/DavidBoike/orgs","repos_url":"https://api.github.com/users/DavidBoike/repos","events_url":"https://api.github.com/users/DavidBoike/events{/privacy}","received_events_url":"https://api.github.com/users/DavidBoike/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114/commits","review_comments_url":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114/comments","review_comment_url":"https://api.github.com/repos/Particular/docs.particular.net/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Particular/docs.particular.net/issues/2114/comments","statuses_url":"https://api.github.com/repos/Particular/docs.particular.net/statuses/12aa546e8652e632136333a38251ecfdd855ed45","head":{"label":"Particular:nsb101-with-renderer","ref":"nsb101-with-renderer","sha":"12aa546e8652e632136333a38251ecfdd855ed45","user":{"login":"Particular","id":5038441,"avatar_url":"https://avatars.githubusercontent.com/u/5038441?v=3","gravatar_id":"","url":"https://api.github.com/users/Particular","html_url":"https://github.com/Particular","followers_url":"https://api.github.com/users/Particular/followers","following_url":"https://api.github.com/users/Particular/following{/other_user}","gists_url":"https://api.github.com/users/Particular/gists{/gist_id}","starred_url":"https://api.github.com/users/Particular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Particular/subscriptions","organizations_url":"https://api.github.com/users/Particular/orgs","repos_url":"https://api.github.com/users/Particular/repos","events_url":"https://api.github.com/users/Particular/events{/privacy}","received_events_url":"https://api.github.com/users/Particular/received_events","type":"Organization","site_admin":false},"repo":{"id":11727301,"name":"docs.particular.net","full_name":"Particular/docs.particular.net","owner":{"login":"Particular","id":5038441,"avatar_url":"https://avatars.githubusercontent.com/u/5038441?v=3","gravatar_id":"","url":"https://api.github.com/users/Particular","html_url":"https://github.com/Particular","followers_url":"https://api.github.com/users/Particular/followers","following_url":"https://api.github.com/users/Particular/following{/other_user}","gists_url":"https://api.github.com/users/Particular/gists{/gist_id}","starred_url":"https://api.github.com/users/Particular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Particular/subscriptions","organizations_url":"https://api.github.com/users/Particular/orgs","repos_url":"https://api.github.com/users/Particular/repos","events_url":"https://api.github.com/users/Particular/events{/privacy}","received_events_url":"https://api.github.com/users/Particular/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Particular/docs.particular.net","description":"Contains all the content for the Particular Developer Portal","fork":false,"url":"https://api.github.com/repos/Particular/docs.particular.net","forks_url":"https://api.github.com/repos/Particular/docs.particular.net/forks","keys_url":"https://api.github.com/repos/Particular/docs.particular.net/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Particular/docs.particular.net/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Particular/docs.particular.net/teams","hooks_url":"https://api.github.com/repos/Particular/docs.particular.net/hooks","issue_events_url":"https://api.github.com/repos/Particular/docs.particular.net/issues/events{/number}","events_url":"https://api.github.com/repos/Particular/docs.particular.net/events","assignees_url":"https://api.github.com/repos/Particular/docs.particular.net/assignees{/user}","branches_url":"https://api.github.com/repos/Particular/docs.particular.net/branches{/branch}","tags_url":"https://api.github.com/repos/Particular/docs.particular.net/tags","blobs_url":"https://api.github.com/repos/Particular/docs.particular.net/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Particular/docs.particular.net/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Particular/docs.particular.net/git/refs{/sha}","trees_url":"https://api.github.com/repos/Particular/docs.particular.net/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Particular/docs.particular.net/statuses/{sha}","languages_url":"https://api.github.com/repos/Particular/docs.particular.net/languages","stargazers_url":"https://api.github.com/repos/Particular/docs.particular.net/stargazers","contributors_url":"https://api.github.com/repos/Particular/docs.particular.net/contributors","subscribers_url":"https://api.github.com/repos/Particular/docs.particular.net/subscribers","subscription_url":"https://api.github.com/repos/Particular/docs.particular.net/subscription","commits_url":"https://api.github.com/repos/Particular/docs.particular.net/commits{/sha}","git_commits_url":"https://api.github.com/repos/Particular/docs.particular.net/git/commits{/sha}","comments_url":"https://api.github.com/repos/Particular/docs.particular.net/comments{/number}","issue_comment_url":"https://api.github.com/repos/Particular/docs.particular.net/issues/comments{/number}","contents_url":"https://api.github.com/repos/Particular/docs.particular.net/contents/{+path}","compare_url":"https://api.github.com/repos/Particular/docs.particular.net/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Particular/docs.particular.net/merges","archive_url":"https://api.github.com/repos/Particular/docs.particular.net/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Particular/docs.particular.net/downloads","issues_url":"https://api.github.com/repos/Particular/docs.particular.net/issues{/number}","pulls_url":"https://api.github.com/repos/Particular/docs.particular.net/pulls{/number}","milestones_url":"https://api.github.com/repos/Particular/docs.particular.net/milestones{/number}","notifications_url":"https://api.github.com/repos/Particular/docs.particular.net/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Particular/docs.particular.net/labels{/name}","releases_url":"https://api.github.com/repos/Particular/docs.particular.net/releases{/id}","deployments_url":"https://api.github.com/repos/Particular/docs.particular.net/deployments","created_at":"2013-07-28T23:18:15Z","updated_at":"2016-10-28T09:46:46Z","pushed_at":"2016-10-31T23:15:59Z","git_url":"git://github.com/Particular/docs.particular.net.git","ssh_url":"git@github.com:Particular/docs.particular.net.git","clone_url":"https://github.com/Particular/docs.particular.net.git","svn_url":"https://github.com/Particular/docs.particular.net","homepage":"https://docs.particular.net","size":63709,"stargazers_count":37,"watchers_count":37,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":152,"mirror_url":null,"open_issues_count":95,"forks":152,"open_issues":95,"watchers":37,"default_branch":"master"}},"base":{"label":"Particular:master","ref":"master","sha":"51e6fb0c5db9209b41d964b53e6a58ba07634a40","user":{"login":"Particular","id":5038441,"avatar_url":"https://avatars.githubusercontent.com/u/5038441?v=3","gravatar_id":"","url":"https://api.github.com/users/Particular","html_url":"https://github.com/Particular","followers_url":"https://api.github.com/users/Particular/followers","following_url":"https://api.github.com/users/Particular/following{/other_user}","gists_url":"https://api.github.com/users/Particular/gists{/gist_id}","starred_url":"https://api.github.com/users/Particular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Particular/subscriptions","organizations_url":"https://api.github.com/users/Particular/orgs","repos_url":"https://api.github.com/users/Particular/repos","events_url":"https://api.github.com/users/Particular/events{/privacy}","received_events_url":"https://api.github.com/users/Particular/received_events","type":"Organization","site_admin":false},"repo":{"id":11727301,"name":"docs.particular.net","full_name":"Particular/docs.particular.net","owner":{"login":"Particular","id":5038441,"avatar_url":"https://avatars.githubusercontent.com/u/5038441?v=3","gravatar_id":"","url":"https://api.github.com/users/Particular","html_url":"https://github.com/Particular","followers_url":"https://api.github.com/users/Particular/followers","following_url":"https://api.github.com/users/Particular/following{/other_user}","gists_url":"https://api.github.com/users/Particular/gists{/gist_id}","starred_url":"https://api.github.com/users/Particular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Particular/subscriptions","organizations_url":"https://api.github.com/users/Particular/orgs","repos_url":"https://api.github.com/users/Particular/repos","events_url":"https://api.github.com/users/Particular/events{/privacy}","received_events_url":"https://api.github.com/users/Particular/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Particular/docs.particular.net","description":"Contains all the content for the Particular Developer Portal","fork":false,"url":"https://api.github.com/repos/Particular/docs.particular.net","forks_url":"https://api.github.com/repos/Particular/docs.particular.net/forks","keys_url":"https://api.github.com/repos/Particular/docs.particular.net/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Particular/docs.particular.net/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Particular/docs.particular.net/teams","hooks_url":"https://api.github.com/repos/Particular/docs.particular.net/hooks","issue_events_url":"https://api.github.com/repos/Particular/docs.particular.net/issues/events{/number}","events_url":"https://api.github.com/repos/Particular/docs.particular.net/events","assignees_url":"https://api.github.com/repos/Particular/docs.particular.net/assignees{/user}","branches_url":"https://api.github.com/repos/Particular/docs.particular.net/branches{/branch}","tags_url":"https://api.github.com/repos/Particular/docs.particular.net/tags","blobs_url":"https://api.github.com/repos/Particular/docs.particular.net/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Particular/docs.particular.net/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Particular/docs.particular.net/git/refs{/sha}","trees_url":"https://api.github.com/repos/Particular/docs.particular.net/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Particular/docs.particular.net/statuses/{sha}","languages_url":"https://api.github.com/repos/Particular/docs.particular.net/languages","stargazers_url":"https://api.github.com/repos/Particular/docs.particular.net/stargazers","contributors_url":"https://api.github.com/repos/Particular/docs.particular.net/contributors","subscribers_url":"https://api.github.com/repos/Particular/docs.particular.net/subscribers","subscription_url":"https://api.github.com/repos/Particular/docs.particular.net/subscription","commits_url":"https://api.github.com/repos/Particular/docs.particular.net/commits{/sha}","git_commits_url":"https://api.github.com/repos/Particular/docs.particular.net/git/commits{/sha}","comments_url":"https://api.github.com/repos/Particular/docs.particular.net/comments{/number}","issue_comment_url":"https://api.github.com/repos/Particular/docs.particular.net/issues/comments{/number}","contents_url":"https://api.github.com/repos/Particular/docs.particular.net/contents/{+path}","compare_url":"https://api.github.com/repos/Particular/docs.particular.net/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Particular/docs.particular.net/merges","archive_url":"https://api.github.com/repos/Particular/docs.particular.net/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Particular/docs.particular.net/downloads","issues_url":"https://api.github.com/repos/Particular/docs.particular.net/issues{/number}","pulls_url":"https://api.github.com/repos/Particular/docs.particular.net/pulls{/number}","milestones_url":"https://api.github.com/repos/Particular/docs.particular.net/milestones{/number}","notifications_url":"https://api.github.com/repos/Particular/docs.particular.net/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Particular/docs.particular.net/labels{/name}","releases_url":"https://api.github.com/repos/Particular/docs.particular.net/releases{/id}","deployments_url":"https://api.github.com/repos/Particular/docs.particular.net/deployments","created_at":"2013-07-28T23:18:15Z","updated_at":"2016-10-28T09:46:46Z","pushed_at":"2016-10-31T23:15:59Z","git_url":"git://github.com/Particular/docs.particular.net.git","ssh_url":"git@github.com:Particular/docs.particular.net.git","clone_url":"https://github.com/Particular/docs.particular.net.git","svn_url":"https://github.com/Particular/docs.particular.net","homepage":"https://docs.particular.net","size":63709,"stargazers_count":37,"watchers_count":37,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":152,"mirror_url":null,"open_issues_count":95,"forks":152,"open_issues":95,"watchers":37,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114"},"html":{"href":"https://github.com/Particular/docs.particular.net/pull/2114"},"issue":{"href":"https://api.github.com/repos/Particular/docs.particular.net/issues/2114"},"comments":{"href":"https://api.github.com/repos/Particular/docs.particular.net/issues/2114/comments"},"review_comments":{"href":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114/comments"},"review_comment":{"href":"https://api.github.com/repos/Particular/docs.particular.net/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Particular/docs.particular.net/pulls/2114/commits"},"statuses":{"href":"https://api.github.com/repos/Particular/docs.particular.net/statuses/12aa546e8652e632136333a38251ecfdd855ed45"}}}}
{"actor":{"display_login":"SimonCropp"}}