{"action":"created","issue":{"url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/issues/238","repository_url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET","labels_url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/issues/238/labels{/name}","comments_url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/issues/238/comments","events_url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/issues/238/events","html_url":"https://github.com/Reactive-Extensions/Rx.NET/issues/238","id":167015445,"number":238,"title":"Possible Bug: Retry does not work on an observable created using the Start operator","user":{"login":"Sathyaish","id":7037893,"avatar_url":"https://avatars.githubusercontent.com/u/7037893?v=3","gravatar_id":"","url":"https://api.github.com/users/Sathyaish","html_url":"https://github.com/Sathyaish","followers_url":"https://api.github.com/users/Sathyaish/followers","following_url":"https://api.github.com/users/Sathyaish/following{/other_user}","gists_url":"https://api.github.com/users/Sathyaish/gists{/gist_id}","starred_url":"https://api.github.com/users/Sathyaish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Sathyaish/subscriptions","organizations_url":"https://api.github.com/users/Sathyaish/orgs","repos_url":"https://api.github.com/users/Sathyaish/repos","events_url":"https://api.github.com/users/Sathyaish/events{/privacy}","received_events_url":"https://api.github.com/users/Sathyaish/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/labels/discussion","name":"discussion","color":"0e8a16"},{"url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/labels/[area]%20Rx","name":"[area] Rx","color":"1d76db"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2016-07-22T10:21:00Z","updated_at":"2016-09-18T03:49:14Z","closed_at":null,"body":"Running the following code snippet only tries the `DownloadString` operation once and gives up on the first failure where it should have retried 3 times before reporting failure.\r\n\r\n```\r\nusing System;\r\nusing System.Net;\r\nusing System.Reactive.Linq;\r\nusing System.Threading;\r\n\r\nnamespace RetryingOperation\r\n{\r\n    class Program\r\n    {\r\n        static void Main(string[] args)\r\n        {\r\n            RetryDownloadStringAsynchronously();\r\n\r\n            Console.WriteLine(\"Press any key to exit the program\");\r\n            Console.ReadKey();\r\n        }\r\n        static void RetryDownloadStringAsynchronously()\r\n        {\r\n            Console.WriteLine($\"Main thread: {Thread.CurrentThread.ManagedThreadId}\");\r\n\r\n            string url = \"http://www.nonexistent.com\";\r\n\r\n            var observable = Observable.Start(() => DownloadString(url));\r\n\r\n            observable.Retry(3).Subscribe(Console.WriteLine, Error, Completed);\r\n        }\r\n\r\n        static void Completed()\r\n        {\r\n            Console.WriteLine(\"The operation completed successfully.\");\r\n        }\r\n\r\n        static void Error(Exception ex)\r\n        {\r\n            Console.WriteLine($\"Error handler reports: There was an error: {ex.Message}\");\r\n        }\r\n\r\n        static string DownloadString(string url)\r\n        {\r\n            try\r\n            {\r\n                Console.WriteLine($\"DownloadString running on thread: {Thread.CurrentThread.ManagedThreadId}\");\r\n\r\n                return new WebClient().DownloadString(url);\r\n            }\r\n            catch\r\n            {\r\n                Console.WriteLine(\"Inside DownloadString: An exception occurred.\");\r\n                throw;\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nPlease note, however, that it works just fine without using the `Start` operator, as shown below.\r\n\r\n```\r\nusing System;\r\nusing System.Net;\r\nusing System.Reactive.Linq;\r\nusing System.Threading;\r\n\r\nnamespace RetryingOperation\r\n{\r\n    class Program\r\n    {\r\n        private static bool flag = false;\r\n\r\n        static void Main(string[] args)\r\n        {\r\n            RetryDownloadString();\r\n\r\n            RetryDownStringEx();\r\n\r\n            Console.WriteLine(\"Press any key to exit the program\");\r\n            Console.ReadKey();\r\n        }\r\n\r\n        static void RetryDownloadString()\r\n        {\r\n            try\r\n            {\r\n                Console.WriteLine($\"Main thread: {Thread.CurrentThread.ManagedThreadId}\");\r\n\r\n                string url = \"http://www.nonexistent.com\";\r\n\r\n                var observable = Observable.Return<Func<string, string>>(DownloadString)\r\n                    .Select(func => func(url));\r\n\r\n                observable.Retry(3).Subscribe(Console.WriteLine, Error, Completed);\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine($\"Catch reports: {ex.Message}\");\r\n            }\r\n        }\r\n\r\n        static void RetryDownStringEx()\r\n        {\r\n            try\r\n            {\r\n\r\n                string url = \"http://www.google.com\";\r\n\r\n                var observable = Observable.Return<Func<string, string>>(DownloadStringEx)\r\n                    .Select(func => func(url));\r\n\r\n                observable.Retry(3).Subscribe(Console.WriteLine, Error, Completed);\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine($\"Catch reports: {ex.Message}\");\r\n            }\r\n        }\r\n\r\n        static void Completed()\r\n        {\r\n            Console.WriteLine(\"The operation completed successfully.\");\r\n        }\r\n\r\n        static void Error(Exception ex)\r\n        {\r\n            Console.WriteLine($\"Error handler reports: There was an error: {ex.Message}\");\r\n        }\r\n\r\n        static string DownloadString(string url)\r\n        {\r\n            try\r\n            {\r\n                Console.WriteLine($\"DownloadString running on thread: {Thread.CurrentThread.ManagedThreadId}\");\r\n\r\n                return new WebClient().DownloadString(url);\r\n            }\r\n            catch\r\n            {\r\n                Console.WriteLine(\"Inside DownloadString: An exception occurred.\");\r\n                throw;\r\n            }\r\n        }\r\n\r\n        static string DownloadStringEx(string url)\r\n        {\r\n            try\r\n            {\r\n                Console.WriteLine($\"DownloadStringEx running on thread: {Thread.CurrentThread.ManagedThreadId}\");\r\n\r\n                if (!flag) url = \"http://invalidUrl\";\r\n\r\n                return new WebClient().DownloadString(url).Length.ToString();\r\n            }\r\n            catch\r\n            {\r\n                flag = !flag;\r\n                Console.WriteLine(\"Inside DownloadStringEx catch: Ooops!\");\r\n                throw;\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nAlso note that it works just fine when not using the `Start` operator even if I were to schedule the work on the default pool scheduler, as the code snippet below shows:\r\n\r\n```\r\nstatic void RetryDownloadString()\r\n{\r\n\ttry\r\n\t{\r\n\t\tConsole.WriteLine($\"Main thread: {Thread.CurrentThread.ManagedThreadId}\");\r\n\r\n\t\tstring url = \"http://www.nonexistent.com\";\r\n\r\n\t\tvar observable = Observable.Return<Func<string, string>>(DownloadString, Scheduler.Default)\r\n\t\t\t.Select(func => func(url));\r\n\r\n\t\tobservable.Retry(3).Subscribe(Console.WriteLine, Error, Completed);\r\n\t}\r\n\tcatch (Exception ex)\r\n\t{\r\n\t\tConsole.WriteLine($\"Catch reports: {ex.Message}\");\r\n\t}\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/issues/comments/247823505","html_url":"https://github.com/Reactive-Extensions/Rx.NET/issues/238#issuecomment-247823505","issue_url":"https://api.github.com/repos/Reactive-Extensions/Rx.NET/issues/238","id":247823505,"user":{"login":"Sathyaish","id":7037893,"avatar_url":"https://avatars.githubusercontent.com/u/7037893?v=3","gravatar_id":"","url":"https://api.github.com/users/Sathyaish","html_url":"https://github.com/Sathyaish","followers_url":"https://api.github.com/users/Sathyaish/followers","following_url":"https://api.github.com/users/Sathyaish/following{/other_user}","gists_url":"https://api.github.com/users/Sathyaish/gists{/gist_id}","starred_url":"https://api.github.com/users/Sathyaish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Sathyaish/subscriptions","organizations_url":"https://api.github.com/users/Sathyaish/orgs","repos_url":"https://api.github.com/users/Sathyaish/repos","events_url":"https://api.github.com/users/Sathyaish/events{/privacy}","received_events_url":"https://api.github.com/users/Sathyaish/received_events","type":"User","site_admin":false},"created_at":"2016-09-18T03:49:14Z","updated_at":"2016-09-18T03:49:14Z","body":"Thanks, @bartdesmet.\r\n\r\nWhy shouldn't it be possible to retry observing a hot sequence if an attempt to observe fails?\r\n\r\nIs that because hot sequences are thought of as being \"out of the control of the observer\" and as having potential side-effects? So retrying them simply because an observation (and not the event itself) failed could mean replaying unintended side-effects?\r\n\r\nIn contrast, a cold observable is, by design, meant to be replayed for each subscriber, so retrying them is quite safe?\r\n\r\nI am now suddenly left wondering, when we retry, what are we actually retrying? Are we retrying:\r\n\r\n1. Running the observable again? or\r\n2. Simply retrying an attempt to observe an observable?\r\n\r\nIn both cases, though, you're right, retrying a hot observable makes little sense."}}
{"actor":{"display_login":"Sathyaish"}}