{"action":"created","comment":{"url":"https://api.github.com/repos/studygolang/GCTT/pulls/comments/234652876","pull_request_review_id":176332467,"id":234652876,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzNDY1Mjg3Ng==","diff_hunk":"@@ -0,0 +1,203 @@\n+# Go中的优雅升级\n+\n+优化升级背后的想法是在进程运行过程中，在用户无感知的情况下对程序的配置和代码进行更换(升级)。尽管这听起来很危险、容易出错、不可取，并且像是一个馊主意 - 事实上我(的想法)和你一样。 但是，有些时候你的确需要它们。这通常在一个没有负载均衡层的环境中会遇到这种问题。我们在*Cloudfare*也遇到了这种情况，这使得我们必须研究这类问题、并尝试、实现各类的解决方案。\n+\n+![](https://blog.cloudflare.com/content/images/2018/10/thing.jpg)\n+*Dingle Dangle! by [Grant C](https://www.flickr.com/photos/grant_subaru/14175646490). (CC-BY 2.0) 可以理解成在汽车行驶的过程中更换发送动机。*\n+\n+巧合的是，在尝试、实现优雅升级的过程中涉及到了一些有趣的底层系统编程知识，这或许就是为什么现在已经有了许多优秀的解决方案。通过深入阅读它们以了解在什么地方需要折衷，以及为什么你需要使用我们即将开源的Go库。当然，如果你觉得我们过于啰嗦，你也可以直接去[github](https://github.com/cloudflare/tableflip)翻阅相关代码，或者在[godoc](https://godoc.org/github.com/cloudflare/tableflip)上阅读我们的文档。\n+\n+## 基础\n+\n+那么一个进程执行优雅升级到底意味着什么？让我们用一个web服务器作为例子：在优雅升级发生的时候，我们希望正在进行的HTTP请求不会中断，而且不会看到任何错误信息。\n+\n+我们知道HTTP连接是建立在TCP连接之上的，我们使用了BSD套接字API的TCP接口。然后我们告诉操作系统我们希望在`80`端口上接收连接请求，然后操作系统分配给我们一个监听中的套接字，我们在这个套接字上调用`Accept()`等待新的客户端连接请求。\n+\n+如果操作系统在`80`端口上没有处于监听的套接字，或者没有任何东西在套接字上调用`Accept()`，那么新的客户端连接请求将会被拒绝。优雅升级的诀窍就在于当我们因为某些原因需要重启我们的服务时，这两件事情都不会发生。那么现在就让我们由简入深地看看如何实现这种方式吧。\n+\n+## 仅使用`Exec()`\n+\n+好吧，我们先看看实现它有多困难。我们先仅仅使用`Exec()`调用来创建一个新的二进制执行程序（而不是一开始就`fork`它）。来将正在运行的代码替换成磁盘中新的代码，这就是我们想要做的。\n+\n+```go\n+// The following is pseudo-Go.\n+\n+func main() {\n+\tvar ln net.Listener\n+\tif isUpgrade {\n+\t\tln = net.FileListener(os.NewFile(uintptr(fdNumber), \"listener\"))\n+\t} else {\n+\t\tln = net.Listen(network, address)\n+\t}\n+\n+\tgo handleRequests(ln)\n+\n+\t<-waitForUpgradeRequest\n+\n+\tsyscall.Exec(os.Argv[0], os.Argv[1:], os.Environ())\n+}\n+```\n+\n+不幸的是，上述代码中有个致命的缺陷，那就是我们不能“撤销”该次执行。设想一下，如果我们的配置文件有很多空白行或者有一个额外的分号。那么这个新的进程在会读取这个配置文件时会得到一个错误，接着新进程就会退出。\n+\n+即使这个执行(exec)执行成功了，这个解决方案也只是假设这个进程的启动是瞬时完成的。我们也可能会遇到内核拒绝新的连接的情况，这是因为TCP会有[监听队列溢出的情况](https://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html)。\n+\n+![](https://blog.cloudflare.com/content/images/2018/10/Example1-1.png)\n+\n+_如果不频繁地调用`Accept()`，那么新的连接可能会被丢弃。_\n+\n+具体来说，新的二进制文件会在`Exec()`之后初始化的过程中花费一些时间进行初始化，这将会导致`Accept()`调用被推迟。这意味着新的连接将会持续堆积，直到一些连接被丢弃。所以普通的`Exec()`调用并不能完成优雅升级的工作。\n+\n+## `监听`(`Listen()`)一切\n+\n+刚才使用的`Exec()`调用并不能解决我们的问题，所以我们需要尝试下一种更好的方案。如果我们`fork`然后`exec`一个新的进程，然后按照它通用的启动例程开始。在某些时候，它会通过监听某些地址来创建套接字，但是可能会由于`errno 48`(也被称为地址已经被使用)的错误返回码而导致这些套接字无法立即开始工作。这是因为操作系统内核阻止了我们想要在旧进程使用的地址和端口上进行监听的操作。\n+\n+当然，有一个标志位可以解决这个问题：`SO_REUSEPORT`。 这个标志位将告诉内核一个事实：即复用给定的端口和地址已经存在监听的套接字，而不是分配一个新的。\n+\n+```go\n+func main() {\n+\tln := net.ListenWithReusePort(network, address)\n+\n+\tgo handleRequests(ln)\n+\n+\t<-waitForUpgradeRequest\n+\n+\tcmd := exec.Command(os.Argv[0], os.Argv[1:])\n+\tcmd.Start()\n+\n+\t<-waitForNewProcess\n+}\n+```\n+\n+那么现在两个进程都在相同的套接字上监听，并且升级的工作也在正常进行。对不对？\n+\n+`SO_REUSEPORT`特性在内核中的作用有点怪异。作为系统开发人员，我们倾向于将套接字视为套接字调用返回的文件描述符。然而内核却将套接字的数据结构和指向该套接字一个或多个文件描述符作了区分。如果你使用了`SO_REUSEPORT`标志位，内核将会创建一个独立的套接字结构体，而不是另一个文件描述符。因此，新旧两个进程分别指向了两个独立的套接字，却碰巧共享了相同的地址。这就导致了一个不可避免的竞态条件：旧进程使用的套接字上新创建的，但尚未被接收的连接将会被内核孤立并杀死。**Github** [写了一篇关于这个问题的优秀博客](https://githubengineering.com/glb-part-2-haproxy-zero-downtime-zero-delay-reloads-with-multibinder/#haproxy-almost-safe-reloads)。\n+\n+**Github** 的工程师使用了`sendmsg`系统调用上的一个[名为: 辅助数据](http://man7.org/linux/man-pages/man0/sys_socket.h.0p.html)的模糊特性解决了`SO_REUSEPORT`的问题。事实证明，辅助数据可以包含文件描述符，使用这个系统调用API对于**Github**来说是有意义的，因为它(这个API)允许了他们k可以优雅地和HAProxy进行集成。由于我们可以随意地更改程序，因此我们可以使用更加简单的替代方案。","path":"translated/tech/20181105-graceful-upgrades-in-go.md","position":76,"original_position":76,"commit_id":"be1cef3992106426ba34182c5076cd0e5421b351","original_commit_id":"be1cef3992106426ba34182c5076cd0e5421b351","user":{"login":"polaris1119","id":899673,"node_id":"MDQ6VXNlcjg5OTY3Mw==","avatar_url":"https://avatars1.githubusercontent.com/u/899673?v=4","gravatar_id":"","url":"https://api.github.com/users/polaris1119","html_url":"https://github.com/polaris1119","followers_url":"https://api.github.com/users/polaris1119/followers","following_url":"https://api.github.com/users/polaris1119/following{/other_user}","gists_url":"https://api.github.com/users/polaris1119/gists{/gist_id}","starred_url":"https://api.github.com/users/polaris1119/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/polaris1119/subscriptions","organizations_url":"https://api.github.com/users/polaris1119/orgs","repos_url":"https://api.github.com/users/polaris1119/repos","events_url":"https://api.github.com/users/polaris1119/events{/privacy}","received_events_url":"https://api.github.com/users/polaris1119/received_events","type":"User","site_admin":false},"body":"们k可以优雅地 -> 多了个 k","created_at":"2018-11-19T15:06:22Z","updated_at":"2018-11-19T15:22:12Z","html_url":"https://github.com/studygolang/GCTT/pull/899#discussion_r234652876","pull_request_url":"https://api.github.com/repos/studygolang/GCTT/pulls/899","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/comments/234652876"},"html":{"href":"https://github.com/studygolang/GCTT/pull/899#discussion_r234652876"},"pull_request":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/899"}}},"pull_request":{"url":"https://api.github.com/repos/studygolang/GCTT/pulls/899","id":228364673,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI4MzY0Njcz","html_url":"https://github.com/studygolang/GCTT/pull/899","diff_url":"https://github.com/studygolang/GCTT/pull/899.diff","patch_url":"https://github.com/studygolang/GCTT/pull/899.patch","issue_url":"https://api.github.com/repos/studygolang/GCTT/issues/899","number":899,"state":"open","locked":false,"title":"【翻译完成】 20181105-graceful-upgrades-in-go.md","user":{"login":"barryz","id":16658738,"node_id":"MDQ6VXNlcjE2NjU4NzM4","avatar_url":"https://avatars0.githubusercontent.com/u/16658738?v=4","gravatar_id":"","url":"https://api.github.com/users/barryz","html_url":"https://github.com/barryz","followers_url":"https://api.github.com/users/barryz/followers","following_url":"https://api.github.com/users/barryz/following{/other_user}","gists_url":"https://api.github.com/users/barryz/gists{/gist_id}","starred_url":"https://api.github.com/users/barryz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/barryz/subscriptions","organizations_url":"https://api.github.com/users/barryz/orgs","repos_url":"https://api.github.com/users/barryz/repos","events_url":"https://api.github.com/users/barryz/events{/privacy}","received_events_url":"https://api.github.com/users/barryz/received_events","type":"User","site_admin":false},"body":"#893 ","created_at":"2018-11-05T14:09:49Z","updated_at":"2018-11-19T15:22:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"38c3c3c503a187e6e4cc8d562b102a67584508f3","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":860251268,"node_id":"MDU6TGFiZWw4NjAyNTEyNjg=","url":"https://api.github.com/repos/studygolang/GCTT/labels/%E6%A0%A1%E5%AF%B9%E4%B8%AD","name":"校对中","color":"81e2c4","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/studygolang/GCTT/pulls/899/commits","review_comments_url":"https://api.github.com/repos/studygolang/GCTT/pulls/899/comments","review_comment_url":"https://api.github.com/repos/studygolang/GCTT/pulls/comments{/number}","comments_url":"https://api.github.com/repos/studygolang/GCTT/issues/899/comments","statuses_url":"https://api.github.com/repos/studygolang/GCTT/statuses/be1cef3992106426ba34182c5076cd0e5421b351","head":{"label":"barryz:graceful_upgrades_in_Go","ref":"graceful_upgrades_in_Go","sha":"be1cef3992106426ba34182c5076cd0e5421b351","user":{"login":"barryz","id":16658738,"node_id":"MDQ6VXNlcjE2NjU4NzM4","avatar_url":"https://avatars0.githubusercontent.com/u/16658738?v=4","gravatar_id":"","url":"https://api.github.com/users/barryz","html_url":"https://github.com/barryz","followers_url":"https://api.github.com/users/barryz/followers","following_url":"https://api.github.com/users/barryz/following{/other_user}","gists_url":"https://api.github.com/users/barryz/gists{/gist_id}","starred_url":"https://api.github.com/users/barryz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/barryz/subscriptions","organizations_url":"https://api.github.com/users/barryz/orgs","repos_url":"https://api.github.com/users/barryz/repos","events_url":"https://api.github.com/users/barryz/events{/privacy}","received_events_url":"https://api.github.com/users/barryz/received_events","type":"User","site_admin":false},"repo":{"id":156081021,"node_id":"MDEwOlJlcG9zaXRvcnkxNTYwODEwMjE=","name":"GCTT","full_name":"barryz/GCTT","private":false,"owner":{"login":"barryz","id":16658738,"node_id":"MDQ6VXNlcjE2NjU4NzM4","avatar_url":"https://avatars0.githubusercontent.com/u/16658738?v=4","gravatar_id":"","url":"https://api.github.com/users/barryz","html_url":"https://github.com/barryz","followers_url":"https://api.github.com/users/barryz/followers","following_url":"https://api.github.com/users/barryz/following{/other_user}","gists_url":"https://api.github.com/users/barryz/gists{/gist_id}","starred_url":"https://api.github.com/users/barryz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/barryz/subscriptions","organizations_url":"https://api.github.com/users/barryz/orgs","repos_url":"https://api.github.com/users/barryz/repos","events_url":"https://api.github.com/users/barryz/events{/privacy}","received_events_url":"https://api.github.com/users/barryz/received_events","type":"User","site_admin":false},"html_url":"https://github.com/barryz/GCTT","description":"GCTT Go中文网翻译组。","fork":true,"url":"https://api.github.com/repos/barryz/GCTT","forks_url":"https://api.github.com/repos/barryz/GCTT/forks","keys_url":"https://api.github.com/repos/barryz/GCTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/barryz/GCTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/barryz/GCTT/teams","hooks_url":"https://api.github.com/repos/barryz/GCTT/hooks","issue_events_url":"https://api.github.com/repos/barryz/GCTT/issues/events{/number}","events_url":"https://api.github.com/repos/barryz/GCTT/events","assignees_url":"https://api.github.com/repos/barryz/GCTT/assignees{/user}","branches_url":"https://api.github.com/repos/barryz/GCTT/branches{/branch}","tags_url":"https://api.github.com/repos/barryz/GCTT/tags","blobs_url":"https://api.github.com/repos/barryz/GCTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/barryz/GCTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/barryz/GCTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/barryz/GCTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/barryz/GCTT/statuses/{sha}","languages_url":"https://api.github.com/repos/barryz/GCTT/languages","stargazers_url":"https://api.github.com/repos/barryz/GCTT/stargazers","contributors_url":"https://api.github.com/repos/barryz/GCTT/contributors","subscribers_url":"https://api.github.com/repos/barryz/GCTT/subscribers","subscription_url":"https://api.github.com/repos/barryz/GCTT/subscription","commits_url":"https://api.github.com/repos/barryz/GCTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/barryz/GCTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/barryz/GCTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/barryz/GCTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/barryz/GCTT/contents/{+path}","compare_url":"https://api.github.com/repos/barryz/GCTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/barryz/GCTT/merges","archive_url":"https://api.github.com/repos/barryz/GCTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/barryz/GCTT/downloads","issues_url":"https://api.github.com/repos/barryz/GCTT/issues{/number}","pulls_url":"https://api.github.com/repos/barryz/GCTT/pulls{/number}","milestones_url":"https://api.github.com/repos/barryz/GCTT/milestones{/number}","notifications_url":"https://api.github.com/repos/barryz/GCTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/barryz/GCTT/labels{/name}","releases_url":"https://api.github.com/repos/barryz/GCTT/releases{/id}","deployments_url":"https://api.github.com/repos/barryz/GCTT/deployments","created_at":"2018-11-04T12:43:03Z","updated_at":"2018-11-05T14:05:01Z","pushed_at":"2018-11-16T07:52:01Z","git_url":"git://github.com/barryz/GCTT.git","ssh_url":"git@github.com:barryz/GCTT.git","clone_url":"https://github.com/barryz/GCTT.git","svn_url":"https://github.com/barryz/GCTT","homepage":"https://studygolang.com/gctt","size":13692,"stargazers_count":0,"watchers_count":0,"language":"Shell","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"studygolang:master","ref":"master","sha":"4125b96327f3c712c5d5f961b5ce37f4dd8d153e","user":{"login":"studygolang","id":3772217,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3NzIyMTc=","avatar_url":"https://avatars3.githubusercontent.com/u/3772217?v=4","gravatar_id":"","url":"https://api.github.com/users/studygolang","html_url":"https://github.com/studygolang","followers_url":"https://api.github.com/users/studygolang/followers","following_url":"https://api.github.com/users/studygolang/following{/other_user}","gists_url":"https://api.github.com/users/studygolang/gists{/gist_id}","starred_url":"https://api.github.com/users/studygolang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/studygolang/subscriptions","organizations_url":"https://api.github.com/users/studygolang/orgs","repos_url":"https://api.github.com/users/studygolang/repos","events_url":"https://api.github.com/users/studygolang/events{/privacy}","received_events_url":"https://api.github.com/users/studygolang/received_events","type":"Organization","site_admin":false},"repo":{"id":110936509,"node_id":"MDEwOlJlcG9zaXRvcnkxMTA5MzY1MDk=","name":"GCTT","full_name":"studygolang/GCTT","private":false,"owner":{"login":"studygolang","id":3772217,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3NzIyMTc=","avatar_url":"https://avatars3.githubusercontent.com/u/3772217?v=4","gravatar_id":"","url":"https://api.github.com/users/studygolang","html_url":"https://github.com/studygolang","followers_url":"https://api.github.com/users/studygolang/followers","following_url":"https://api.github.com/users/studygolang/following{/other_user}","gists_url":"https://api.github.com/users/studygolang/gists{/gist_id}","starred_url":"https://api.github.com/users/studygolang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/studygolang/subscriptions","organizations_url":"https://api.github.com/users/studygolang/orgs","repos_url":"https://api.github.com/users/studygolang/repos","events_url":"https://api.github.com/users/studygolang/events{/privacy}","received_events_url":"https://api.github.com/users/studygolang/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/studygolang/GCTT","description":"GCTT Go中文网翻译组。","fork":false,"url":"https://api.github.com/repos/studygolang/GCTT","forks_url":"https://api.github.com/repos/studygolang/GCTT/forks","keys_url":"https://api.github.com/repos/studygolang/GCTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/studygolang/GCTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/studygolang/GCTT/teams","hooks_url":"https://api.github.com/repos/studygolang/GCTT/hooks","issue_events_url":"https://api.github.com/repos/studygolang/GCTT/issues/events{/number}","events_url":"https://api.github.com/repos/studygolang/GCTT/events","assignees_url":"https://api.github.com/repos/studygolang/GCTT/assignees{/user}","branches_url":"https://api.github.com/repos/studygolang/GCTT/branches{/branch}","tags_url":"https://api.github.com/repos/studygolang/GCTT/tags","blobs_url":"https://api.github.com/repos/studygolang/GCTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/studygolang/GCTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/studygolang/GCTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/studygolang/GCTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/studygolang/GCTT/statuses/{sha}","languages_url":"https://api.github.com/repos/studygolang/GCTT/languages","stargazers_url":"https://api.github.com/repos/studygolang/GCTT/stargazers","contributors_url":"https://api.github.com/repos/studygolang/GCTT/contributors","subscribers_url":"https://api.github.com/repos/studygolang/GCTT/subscribers","subscription_url":"https://api.github.com/repos/studygolang/GCTT/subscription","commits_url":"https://api.github.com/repos/studygolang/GCTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/studygolang/GCTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/studygolang/GCTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/studygolang/GCTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/studygolang/GCTT/contents/{+path}","compare_url":"https://api.github.com/repos/studygolang/GCTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/studygolang/GCTT/merges","archive_url":"https://api.github.com/repos/studygolang/GCTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/studygolang/GCTT/downloads","issues_url":"https://api.github.com/repos/studygolang/GCTT/issues{/number}","pulls_url":"https://api.github.com/repos/studygolang/GCTT/pulls{/number}","milestones_url":"https://api.github.com/repos/studygolang/GCTT/milestones{/number}","notifications_url":"https://api.github.com/repos/studygolang/GCTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/studygolang/GCTT/labels{/name}","releases_url":"https://api.github.com/repos/studygolang/GCTT/releases{/id}","deployments_url":"https://api.github.com/repos/studygolang/GCTT/deployments","created_at":"2017-11-16T07:10:44Z","updated_at":"2018-11-19T02:37:07Z","pushed_at":"2018-11-19T12:46:28Z","git_url":"git://github.com/studygolang/GCTT.git","ssh_url":"git@github.com:studygolang/GCTT.git","clone_url":"https://github.com/studygolang/GCTT.git","svn_url":"https://github.com/studygolang/GCTT","homepage":"https://studygolang.com/gctt","size":13779,"stargazers_count":649,"watchers_count":649,"language":"Shell","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":288,"mirror_url":null,"archived":false,"open_issues_count":37,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":288,"open_issues":37,"watchers":649,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/899"},"html":{"href":"https://github.com/studygolang/GCTT/pull/899"},"issue":{"href":"https://api.github.com/repos/studygolang/GCTT/issues/899"},"comments":{"href":"https://api.github.com/repos/studygolang/GCTT/issues/899/comments"},"review_comments":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/899/comments"},"review_comment":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/899/commits"},"statuses":{"href":"https://api.github.com/repos/studygolang/GCTT/statuses/be1cef3992106426ba34182c5076cd0e5421b351"}},"author_association":"NONE"}}
{"actor":{"display_login":"polaris1119"}}