{"action":"created","comment":{"url":"https://api.github.com/repos/flynn/flynn/pulls/comments/45879596","id":45879596,"diff_hunk":"@@ -0,0 +1,196 @@\n+package deployment\n+\n+import (\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"time\"\n+\n+\t\"github.com/flynn/flynn/Godeps/_workspace/src/gopkg.in/inconshreveable/log15.v2\"\n+\t\"github.com/flynn/flynn/discoverd/client\"\n+\t\"github.com/flynn/flynn/pkg/attempt\"\n+\t\"github.com/flynn/flynn/pkg/stream\"\n+)\n+\n+type DeploymentState string\n+\n+const (\n+\tDeploymentStatePerforming DeploymentState = \"performing\"\n+\tDeploymentStateDone       DeploymentState = \"done\"\n+)\n+\n+func NewDeployment(service string) (*Deployment, error) {\n+\ts := discoverd.NewService(service)\n+\tevents := make(chan *discoverd.Event)\n+\tstream, err := s.Watch(events)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\treturn &Deployment{s, events, stream}, nil\n+}\n+\n+// Deployment is a wrapper around service metadata for marking jobs as either\n+// performing a deployment or done deploying\n+type Deployment struct {\n+\tservice discoverd.Service\n+\tevents  chan *discoverd.Event\n+\tstream  stream.Stream\n+}\n+\n+const deploymentTimeout = time.Minute","path":"discoverd/deployment/deployment.go","position":39,"original_position":39,"commit_id":"a829cefe546d2b17833325bc07d4fbfaee2a1e99","original_commit_id":"a829cefe546d2b17833325bc07d4fbfaee2a1e99","user":{"login":"josephglanville","id":605591,"avatar_url":"https://avatars.githubusercontent.com/u/605591?v=3","gravatar_id":"","url":"https://api.github.com/users/josephglanville","html_url":"https://github.com/josephglanville","followers_url":"https://api.github.com/users/josephglanville/followers","following_url":"https://api.github.com/users/josephglanville/following{/other_user}","gists_url":"https://api.github.com/users/josephglanville/gists{/gist_id}","starred_url":"https://api.github.com/users/josephglanville/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/josephglanville/subscriptions","organizations_url":"https://api.github.com/users/josephglanville/orgs","repos_url":"https://api.github.com/users/josephglanville/repos","events_url":"https://api.github.com/users/josephglanville/events{/privacy}","received_events_url":"https://api.github.com/users/josephglanville/received_events","type":"User","site_admin":false},"body":"Actually I am not sure about this. The timeout should probably be configurable but it's not clear of `app.DeployTimeout` is directly comparable to the `deploymentTimeout` used here as it's used to both determine the amount of time we spend trying to mark ourselves performing and how long we wait for all `done` events to arrive. I am thinking if we do want to use app.DeploymentTimeout it should be given as an argument to `Wait()` as it's the only place this information is needed or even relevant.\r\nThe same could probably be said for the mark performing stage, it should be up to the application to choose how long is reasonable enough to wait for other nodes to finish.","created_at":"2015-11-25T15:29:25Z","updated_at":"2015-11-25T15:29:25Z","html_url":"https://github.com/flynn/flynn/pull/2003#discussion_r45879596","pull_request_url":"https://api.github.com/repos/flynn/flynn/pulls/2003","_links":{"self":{"href":"https://api.github.com/repos/flynn/flynn/pulls/comments/45879596"},"html":{"href":"https://github.com/flynn/flynn/pull/2003#discussion_r45879596"},"pull_request":{"href":"https://api.github.com/repos/flynn/flynn/pulls/2003"}}},"pull_request":{"url":"https://api.github.com/repos/flynn/flynn/pulls/2003","id":48339916,"html_url":"https://github.com/flynn/flynn/pull/2003","diff_url":"https://github.com/flynn/flynn/pull/2003.diff","patch_url":"https://github.com/flynn/flynn/pull/2003.patch","issue_url":"https://api.github.com/repos/flynn/flynn/issues/2003","number":2003,"state":"open","locked":false,"title":"Update discoverd","user":{"login":"josephglanville","id":605591,"avatar_url":"https://avatars.githubusercontent.com/u/605591?v=3","gravatar_id":"","url":"https://api.github.com/users/josephglanville","html_url":"https://github.com/josephglanville","followers_url":"https://api.github.com/users/josephglanville/followers","following_url":"https://api.github.com/users/josephglanville/following{/other_user}","gists_url":"https://api.github.com/users/josephglanville/gists{/gist_id}","starred_url":"https://api.github.com/users/josephglanville/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/josephglanville/subscriptions","organizations_url":"https://api.github.com/users/josephglanville/orgs","repos_url":"https://api.github.com/users/josephglanville/repos","events_url":"https://api.github.com/users/josephglanville/events{/privacy}","received_events_url":"https://api.github.com/users/josephglanville/received_events","type":"User","site_admin":false},"body":"This patchset implements an in-place update of the discoverd service.\r\n\r\nThe process is as follows:\r\n\r\n1. A discoverd deployment is triggered\r\n2. The controller then creates a \"deployment context\" that describes the state of the discoverd deployment in the discoverd service metadata. This is implemented as a re-usable deployment strategy called \"discoverd-meta\"\r\n3. The controller worker will then scale the formation up, as discoverd is an omnipresent job this means it will spawn new jobs on every node in the cluster.\r\n4. These jobs will upon starting up check to see if there is already a discoverd process listening on the HTTP address they intend to bind to, if so they will connect to it.\r\n5. They will then attempt to mark themselves as \"performing\" in the deployment context, ensuring only one node is marked performing at a time. This is safe because discoverd service metadata is linear.\r\n6. Once it successfully marks itself as performing it will start it's DNS server in proxy mode (using SO_REUSEPORT) and issue a shutdown command to the process it's replacing, acquiring that processes current log position in the process.\r\n7. It will block on the other node shutting down before starting it's Raft store and will wait until it's atleast caught up to the position that the process it replaced was before it starts the HTTP listener.\r\n8. Once reaching this point the process will mark itself as \"done\" in the deployment context.\r\n9. The controller worker watches the discoverd service meta event stream and when all nodes are marked \"done\" it will proceed to scaling down the formation and terminating the now dormant old jobs.\r\n10. Deployment complete.\r\n","created_at":"2015-10-21T14:37:19Z","updated_at":"2015-11-25T15:29:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5dafa70042cfe49a0ce60882712f7c9e674a2b79","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/flynn/flynn/pulls/2003/commits","review_comments_url":"https://api.github.com/repos/flynn/flynn/pulls/2003/comments","review_comment_url":"https://api.github.com/repos/flynn/flynn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/flynn/flynn/issues/2003/comments","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/a829cefe546d2b17833325bc07d4fbfaee2a1e99","head":{"label":"flynn:update-discoverd","ref":"update-discoverd","sha":"a829cefe546d2b17833325bc07d4fbfaee2a1e99","user":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"repo":{"id":11290232,"name":"flynn","full_name":"flynn/flynn","owner":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/flynn/flynn","description":"A next generation open source platform as a service (PaaS)","fork":false,"url":"https://api.github.com/repos/flynn/flynn","forks_url":"https://api.github.com/repos/flynn/flynn/forks","keys_url":"https://api.github.com/repos/flynn/flynn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/flynn/flynn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/flynn/flynn/teams","hooks_url":"https://api.github.com/repos/flynn/flynn/hooks","issue_events_url":"https://api.github.com/repos/flynn/flynn/issues/events{/number}","events_url":"https://api.github.com/repos/flynn/flynn/events","assignees_url":"https://api.github.com/repos/flynn/flynn/assignees{/user}","branches_url":"https://api.github.com/repos/flynn/flynn/branches{/branch}","tags_url":"https://api.github.com/repos/flynn/flynn/tags","blobs_url":"https://api.github.com/repos/flynn/flynn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/flynn/flynn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/flynn/flynn/git/refs{/sha}","trees_url":"https://api.github.com/repos/flynn/flynn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/{sha}","languages_url":"https://api.github.com/repos/flynn/flynn/languages","stargazers_url":"https://api.github.com/repos/flynn/flynn/stargazers","contributors_url":"https://api.github.com/repos/flynn/flynn/contributors","subscribers_url":"https://api.github.com/repos/flynn/flynn/subscribers","subscription_url":"https://api.github.com/repos/flynn/flynn/subscription","commits_url":"https://api.github.com/repos/flynn/flynn/commits{/sha}","git_commits_url":"https://api.github.com/repos/flynn/flynn/git/commits{/sha}","comments_url":"https://api.github.com/repos/flynn/flynn/comments{/number}","issue_comment_url":"https://api.github.com/repos/flynn/flynn/issues/comments{/number}","contents_url":"https://api.github.com/repos/flynn/flynn/contents/{+path}","compare_url":"https://api.github.com/repos/flynn/flynn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/flynn/flynn/merges","archive_url":"https://api.github.com/repos/flynn/flynn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/flynn/flynn/downloads","issues_url":"https://api.github.com/repos/flynn/flynn/issues{/number}","pulls_url":"https://api.github.com/repos/flynn/flynn/pulls{/number}","milestones_url":"https://api.github.com/repos/flynn/flynn/milestones{/number}","notifications_url":"https://api.github.com/repos/flynn/flynn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/flynn/flynn/labels{/name}","releases_url":"https://api.github.com/repos/flynn/flynn/releases{/id}","created_at":"2013-07-09T18:22:06Z","updated_at":"2015-11-25T11:05:00Z","pushed_at":"2015-11-25T15:16:15Z","git_url":"git://github.com/flynn/flynn.git","ssh_url":"git@github.com:flynn/flynn.git","clone_url":"https://github.com/flynn/flynn.git","svn_url":"https://github.com/flynn/flynn","homepage":"https://flynn.io","size":22813,"stargazers_count":4044,"watchers_count":4044,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":288,"mirror_url":null,"open_issues_count":263,"forks":288,"open_issues":263,"watchers":4044,"default_branch":"master"}},"base":{"label":"flynn:master","ref":"master","sha":"1e226e204cb5fe83f7b7ec4e439da7d16ec417bc","user":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"repo":{"id":11290232,"name":"flynn","full_name":"flynn/flynn","owner":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/flynn/flynn","description":"A next generation open source platform as a service (PaaS)","fork":false,"url":"https://api.github.com/repos/flynn/flynn","forks_url":"https://api.github.com/repos/flynn/flynn/forks","keys_url":"https://api.github.com/repos/flynn/flynn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/flynn/flynn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/flynn/flynn/teams","hooks_url":"https://api.github.com/repos/flynn/flynn/hooks","issue_events_url":"https://api.github.com/repos/flynn/flynn/issues/events{/number}","events_url":"https://api.github.com/repos/flynn/flynn/events","assignees_url":"https://api.github.com/repos/flynn/flynn/assignees{/user}","branches_url":"https://api.github.com/repos/flynn/flynn/branches{/branch}","tags_url":"https://api.github.com/repos/flynn/flynn/tags","blobs_url":"https://api.github.com/repos/flynn/flynn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/flynn/flynn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/flynn/flynn/git/refs{/sha}","trees_url":"https://api.github.com/repos/flynn/flynn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/{sha}","languages_url":"https://api.github.com/repos/flynn/flynn/languages","stargazers_url":"https://api.github.com/repos/flynn/flynn/stargazers","contributors_url":"https://api.github.com/repos/flynn/flynn/contributors","subscribers_url":"https://api.github.com/repos/flynn/flynn/subscribers","subscription_url":"https://api.github.com/repos/flynn/flynn/subscription","commits_url":"https://api.github.com/repos/flynn/flynn/commits{/sha}","git_commits_url":"https://api.github.com/repos/flynn/flynn/git/commits{/sha}","comments_url":"https://api.github.com/repos/flynn/flynn/comments{/number}","issue_comment_url":"https://api.github.com/repos/flynn/flynn/issues/comments{/number}","contents_url":"https://api.github.com/repos/flynn/flynn/contents/{+path}","compare_url":"https://api.github.com/repos/flynn/flynn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/flynn/flynn/merges","archive_url":"https://api.github.com/repos/flynn/flynn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/flynn/flynn/downloads","issues_url":"https://api.github.com/repos/flynn/flynn/issues{/number}","pulls_url":"https://api.github.com/repos/flynn/flynn/pulls{/number}","milestones_url":"https://api.github.com/repos/flynn/flynn/milestones{/number}","notifications_url":"https://api.github.com/repos/flynn/flynn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/flynn/flynn/labels{/name}","releases_url":"https://api.github.com/repos/flynn/flynn/releases{/id}","created_at":"2013-07-09T18:22:06Z","updated_at":"2015-11-25T11:05:00Z","pushed_at":"2015-11-25T15:16:15Z","git_url":"git://github.com/flynn/flynn.git","ssh_url":"git@github.com:flynn/flynn.git","clone_url":"https://github.com/flynn/flynn.git","svn_url":"https://github.com/flynn/flynn","homepage":"https://flynn.io","size":22813,"stargazers_count":4044,"watchers_count":4044,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":288,"mirror_url":null,"open_issues_count":263,"forks":288,"open_issues":263,"watchers":4044,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/flynn/flynn/pulls/2003"},"html":{"href":"https://github.com/flynn/flynn/pull/2003"},"issue":{"href":"https://api.github.com/repos/flynn/flynn/issues/2003"},"comments":{"href":"https://api.github.com/repos/flynn/flynn/issues/2003/comments"},"review_comments":{"href":"https://api.github.com/repos/flynn/flynn/pulls/2003/comments"},"review_comment":{"href":"https://api.github.com/repos/flynn/flynn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/flynn/flynn/pulls/2003/commits"},"statuses":{"href":"https://api.github.com/repos/flynn/flynn/statuses/a829cefe546d2b17833325bc07d4fbfaee2a1e99"}}}}