payload: {"action":"created","comment":{"url":"https://api.github.com/repos/square/quotaservice/pulls/comments/255727273","pull_request_review_id":202380611,"id":255727273,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI1NTcyNzI3Mw==","diff_hunk":"@@ -0,0 +1,210 @@\n+package mysqlpersister\n+\n+import (\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"sort\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\tsq \"github.com/Masterminds/squirrel\"\n+\t_ \"github.com/go-sql-driver/mysql\"\n+\t\"github.com/golang/protobuf/proto\"\n+\t\"github.com/jmoiron/sqlx\"\n+\n+\t\"github.com/square/quotaservice/config\"\n+\t\"github.com/square/quotaservice/logging\"\n+\tqsc \"github.com/square/quotaservice/protos/config\"\n+)\n+\n+type mysqlPersister struct {\n+\tlatestVersion int\n+\tdb            *sqlx.DB\n+\tm             *sync.RWMutex\n+\n+\twatcher  chan struct{}\n+\tshutdown chan struct{}\n+\n+\tactiveFetchers *sync.WaitGroup\n+\n+\tconfigs map[int]*qsc.ServiceConfig\n+}\n+\n+type configRow struct {\n+\tVersion int    `db:\"Version\"`\n+\tConfig  string `db:\"Config\"`\n+}\n+\n+func New(dbUser, dbPass, dbHost string, dbPort int, dbName string, pollingInterval time.Duration) (config.ConfigPersister, error) {\n+\tdb, err := sqlx.Open(\"mysql\",\n+\t\tfmt.Sprintf(\"%s:%s@(%s:%v)/%s\",\n+\t\t\tdbUser,\n+\t\t\tdbPass,\n+\t\t\tdbHost,\n+\t\t\tdbPort,\n+\t\t\tdbName))\n+\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\t_, err = db.Query(\"SELECT 1 FROM quotaservice LIMIT 1\")\n+\tif err != nil {\n+\t\treturn nil, errors.New(\"table quotaservice does not exist\")\n+\t}\n+\n+\tmp := &mysqlPersister{\n+\t\tdb:             db,\n+\t\tconfigs:        make(map[int]*qsc.ServiceConfig),\n+\t\tactiveFetchers: &sync.WaitGroup{},\n+\t\tm:              &sync.RWMutex{},\n+\t\twatcher:        make(chan struct{}),\n+\t\tshutdown:       make(chan struct{}),\n+\t\tlatestVersion:  -1,\n+\t}\n+\n+\tmp.pullConfigs()\n+\n+\tmp.activeFetchers.Add(1)\n+\tgo mp.configFetcher(pollingInterval)\n+\n+\treturn mp, nil\n+}\n+\n+func (mp *mysqlPersister) configFetcher(pollingInterval time.Duration) {\n+\tdefer mp.activeFetchers.Done()\n+\n+\tfor {\n+\t\tselect {\n+\t\tcase <-time.After(pollingInterval):\n+\t\t\tif mp.pullConfigs() {\n+\t\t\t\tmp.notifyWatcher()\n+\t\t\t}\n+\t\tcase <-mp.shutdown:\n+\t\t\tlogging.Print(\"Received shutdown signal, shutting down mysql watcher\")\n+\t\t\treturn\n+\t\t}\n+\t}\n+}\n+\n+// pullConfigs checks the database for new configs and returns true if there is a new config\n+func (mp *mysqlPersister) pullConfigs() bool {\n+\tmp.m.RLock()\n+\tv := mp.latestVersion\n+\tmp.m.RUnlock()\n+\n+\tq, args, err := sq.\n+\t\tSelect(\"Version\", \"Config\").\n+\t\tFrom(\"quotaservice\").\n+\t\tWhere(\"Version > ?\", v).\n+\t\tOrderBy(\"Version ASC\").ToSql()\n+\tif err != nil {\n+\t\tlogging.Printf(\"Could not generate query to fetch config updates: %s\", err)\n+\t\treturn false\n+\t}\n+\n+\tvar rows []*configRow\n+\terr = mp.db.Select(&rows, q, args...)\n+\tif err != nil {\n+\t\tlogging.Printf(\"Received error from querying mysql for the latest configs mysql: %s\", err)","path":"config/mysqlpersister/mysqlpersister.go","position":109,"original_position":109,"commit_id":"7cf0558ecf2c397a8be38ad07ad329ea6236f19b","original_commit_id":"7cf0558ecf2c397a8be38ad07ad329ea6236f19b","user":{"login":"spenceral","id":10701033,"node_id":"MDQ6VXNlcjEwNzAxMDMz","avatar_url":"https://avatars2.githubusercontent.com/u/10701033?v=4","gravatar_id":"","url":"https://api.github.com/users/spenceral","html_url":"https://github.com/spenceral","followers_url":"https://api.github.com/users/spenceral/followers","following_url":"https://api.github.com/users/spenceral/following{/other_user}","gists_url":"https://api.github.com/users/spenceral/gists{/gist_id}","starred_url":"https://api.github.com/users/spenceral/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spenceral/subscriptions","organizations_url":"https://api.github.com/users/spenceral/orgs","repos_url":"https://api.github.com/users/spenceral/repos","events_url":"https://api.github.com/users/spenceral/events{/privacy}","received_events_url":"https://api.github.com/users/spenceral/received_events","type":"User","site_admin":false},"body":"If we bubbled this error up, do you think it would be more clear to debuggers (especially those that aren't reviewing the code now) where the error is coming from?","created_at":"2019-02-11T22:50:40Z","updated_at":"2019-02-11T22:50:41Z","html_url":"https://github.com/square/quotaservice/pull/142#discussion_r255727273","pull_request_url":"https://api.github.com/repos/square/quotaservice/pulls/142","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/square/quotaservice/pulls/comments/255727273"},"html":{"href":"https://github.com/square/quotaservice/pull/142#discussion_r255727273"},"pull_request":{"href":"https://api.github.com/repos/square/quotaservice/pulls/142"}}},"pull_request":{"url":"https://api.github.com/repos/square/quotaservice/pulls/142","id":252060943,"node_id":"MDExOlB1bGxSZXF1ZXN0MjUyMDYwOTQz","html_url":"https://github.com/square/quotaservice/pull/142","diff_url":"https://github.com/square/quotaservice/pull/142.diff","patch_url":"https://github.com/square/quotaservice/pull/142.patch","issue_url":"https://api.github.com/repos/square/quotaservice/issues/142","number":142,"state":"open","locked":false,"title":"MySQL persister implemented","user":{"login":"szabado","id":14365769,"node_id":"MDQ6VXNlcjE0MzY1NzY5","avatar_url":"https://avatars2.githubusercontent.com/u/14365769?v=4","gravatar_id":"","url":"https://api.github.com/users/szabado","html_url":"https://github.com/szabado","followers_url":"https://api.github.com/users/szabado/followers","following_url":"https://api.github.com/users/szabado/following{/other_user}","gists_url":"https://api.github.com/users/szabado/gists{/gist_id}","starred_url":"https://api.github.com/users/szabado/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/szabado/subscriptions","organizations_url":"https://api.github.com/users/szabado/orgs","repos_url":"https://api.github.com/users/szabado/repos","events_url":"https://api.github.com/users/szabado/events{/privacy}","received_events_url":"https://api.github.com/users/szabado/received_events","type":"User","site_admin":false},"body":"There's a LOT of added vendor stuff, most of them stemming from the fact that I included [dockertest](https://github.com/ory/dockertest) to dynamically spin up a MySQL instance for integration testing the persister.\r\n\r\nThe only files aside from `go.mod` and `go.sum` I changed are under `config/mysqlpersister`.","created_at":"2019-02-11T20:55:29Z","updated_at":"2019-02-11T22:50:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":"04f320edb5026866b15adacb982c54663011374c","assignee":null,"assignees":[],"requested_reviewers":[{"login":"maniksurtani","id":47146,"node_id":"MDQ6VXNlcjQ3MTQ2","avatar_url":"https://avatars1.githubusercontent.com/u/47146?v=4","gravatar_id":"","url":"https://api.github.com/users/maniksurtani","html_url":"https://github.com/maniksurtani","followers_url":"https://api.github.com/users/maniksurtani/followers","following_url":"https://api.github.com/users/maniksurtani/following{/other_user}","gists_url":"https://api.github.com/users/maniksurtani/gists{/gist_id}","starred_url":"https://api.github.com/users/maniksurtani/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maniksurtani/subscriptions","organizations_url":"https://api.github.com/users/maniksurtani/orgs","repos_url":"https://api.github.com/users/maniksurtani/repos","events_url":"https://api.github.com/users/maniksurtani/events{/privacy}","received_events_url":"https://api.github.com/users/maniksurtani/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/square/quotaservice/pulls/142/commits","review_comments_url":"https://api.github.com/repos/square/quotaservice/pulls/142/comments","review_comment_url":"https://api.github.com/repos/square/quotaservice/pulls/comments{/number}","comments_url":"https://api.github.com/repos/square/quotaservice/issues/142/comments","statuses_url":"https://api.github.com/repos/square/quotaservice/statuses/7cf0558ecf2c397a8be38ad07ad329ea6236f19b","head":{"label":"square:mysql_persister","ref":"mysql_persister","sha":"7cf0558ecf2c397a8be38ad07ad329ea6236f19b","user":{"login":"square","id":82592,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgyNTky","avatar_url":"https://avatars0.githubusercontent.com/u/82592?v=4","gravatar_id":"","url":"https://api.github.com/users/square","html_url":"https://github.com/square","followers_url":"https://api.github.com/users/square/followers","following_url":"https://api.github.com/users/square/following{/other_user}","gists_url":"https://api.github.com/users/square/gists{/gist_id}","starred_url":"https://api.github.com/users/square/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/square/subscriptions","organizations_url":"https://api.github.com/users/square/orgs","repos_url":"https://api.github.com/users/square/repos","events_url":"https://api.github.com/users/square/events{/privacy}","received_events_url":"https://api.github.com/users/square/received_events","type":"Organization","site_admin":false},"repo":{"id":46589610,"node_id":"MDEwOlJlcG9zaXRvcnk0NjU4OTYxMA==","name":"quotaservice","full_name":"square/quotaservice","private":false,"owner":{"login":"square","id":82592,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgyNTky","avatar_url":"https://avatars0.githubusercontent.com/u/82592?v=4","gravatar_id":"","url":"https://api.github.com/users/square","html_url":"https://github.com/square","followers_url":"https://api.github.com/users/square/followers","following_url":"https://api.github.com/users/square/following{/other_user}","gists_url":"https://api.github.com/users/square/gists{/gist_id}","starred_url":"https://api.github.com/users/square/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/square/subscriptions","organizations_url":"https://api.github.com/users/square/orgs","repos_url":"https://api.github.com/users/square/repos","events_url":"https://api.github.com/users/square/events{/privacy}","received_events_url":"https://api.github.com/users/square/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/square/quotaservice","description":"The purpose of a quota service is to prevent cascading failures in micro-service environments. The service acts as a traffic cop, slowing down traffic where necessary to prevent overloading services. For this to work, remote procedure calls (RPCs) between services consult the quota service before making a call. The service isn’t strictly for RPCs between services, and can even be used to apply quotas to database calls, for example.","fork":false,"url":"https://api.github.com/repos/square/quotaservice","forks_url":"https://api.github.com/repos/square/quotaservice/forks","keys_url":"https://api.github.com/repos/square/quotaservice/keys{/key_id}","collaborators_url":"https://api.github.com/repos/square/quotaservice/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/square/quotaservice/teams","hooks_url":"https://api.github.com/repos/square/quotaservice/hooks","issue_events_url":"https://api.github.com/repos/square/quotaservice/issues/events{/number}","events_url":"https://api.github.com/repos/square/quotaservice/events","assignees_url":"https://api.github.com/repos/square/quotaservice/assignees{/user}","branches_url":"https://api.github.com/repos/square/quotaservice/branches{/branch}","tags_url":"https://api.github.com/repos/square/quotaservice/tags","blobs_url":"https://api.github.com/repos/square/quotaservice/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/square/quotaservice/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/square/quotaservice/git/refs{/sha}","trees_url":"https://api.github.com/repos/square/quotaservice/git/trees{/sha}","statuses_url":"https://api.github.com/repos/square/quotaservice/statuses/{sha}","languages_url":"https://api.github.com/repos/square/quotaservice/languages","stargazers_url":"https://api.github.com/repos/square/quotaservice/stargazers","contributors_url":"https://api.github.com/repos/square/quotaservice/contributors","subscribers_url":"https://api.github.com/repos/square/quotaservice/subscribers","subscription_url":"https://api.github.com/repos/square/quotaservice/subscription","commits_url":"https://api.github.com/repos/square/quotaservice/commits{/sha}","git_commits_url":"https://api.github.com/repos/square/quotaservice/git/commits{/sha}","comments_url":"https://api.github.com/repos/square/quotaservice/comments{/number}","issue_comment_url":"https://api.github.com/repos/square/quotaservice/issues/comments{/number}","contents_url":"https://api.github.com/repos/square/quotaservice/contents/{+path}","compare_url":"https://api.github.com/repos/square/quotaservice/compare/{base}...{head}","merges_url":"https://api.github.com/repos/square/quotaservice/merges","archive_url":"https://api.github.com/repos/square/quotaservice/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/square/quotaservice/downloads","issues_url":"https://api.github.com/repos/square/quotaservice/issues{/number}","pulls_url":"https://api.github.com/repos/square/quotaservice/pulls{/number}","milestones_url":"https://api.github.com/repos/square/quotaservice/milestones{/number}","notifications_url":"https://api.github.com/repos/square/quotaservice/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/square/quotaservice/labels{/name}","releases_url":"https://api.github.com/repos/square/quotaservice/releases{/id}","deployments_url":"https://api.github.com/repos/square/quotaservice/deployments","created_at":"2015-11-20T22:11:12Z","updated_at":"2019-02-11T03:37:19Z","pushed_at":"2019-02-11T22:20:35Z","git_url":"git://github.com/square/quotaservice.git","ssh_url":"git@github.com:square/quotaservice.git","clone_url":"https://github.com/square/quotaservice.git","svn_url":"https://github.com/square/quotaservice","homepage":"","size":15043,"stargazers_count":76,"watchers_count":76,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":18,"mirror_url":null,"archived":false,"open_issues_count":2,"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":18,"open_issues":2,"watchers":76,"default_branch":"master"}},"base":{"label":"square:master","ref":"master","sha":"6d13a4e5938fd55f071971c0ee490d67935db6e8","user":{"login":"square","id":82592,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgyNTky","avatar_url":"https://avatars0.githubusercontent.com/u/82592?v=4","gravatar_id":"","url":"https://api.github.com/users/square","html_url":"https://github.com/square","followers_url":"https://api.github.com/users/square/followers","following_url":"https://api.github.com/users/square/following{/other_user}","gists_url":"https://api.github.com/users/square/gists{/gist_id}","starred_url":"https://api.github.com/users/square/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/square/subscriptions","organizations_url":"https://api.github.com/users/square/orgs","repos_url":"https://api.github.com/users/square/repos","events_url":"https://api.github.com/users/square/events{/privacy}","received_events_url":"https://api.github.com/users/square/received_events","type":"Organization","site_admin":false},"repo":{"id":46589610,"node_id":"MDEwOlJlcG9zaXRvcnk0NjU4OTYxMA==","name":"quotaservice","full_name":"square/quotaservice","private":false,"owner":{"login":"square","id":82592,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgyNTky","avatar_url":"https://avatars0.githubusercontent.com/u/82592?v=4","gravatar_id":"","url":"https://api.github.com/users/square","html_url":"https://github.com/square","followers_url":"https://api.github.com/users/square/followers","following_url":"https://api.github.com/users/square/following{/other_user}","gists_url":"https://api.github.com/users/square/gists{/gist_id}","starred_url":"https://api.github.com/users/square/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/square/subscriptions","organizations_url":"https://api.github.com/users/square/orgs","repos_url":"https://api.github.com/users/square/repos","events_url":"https://api.github.com/users/square/events{/privacy}","received_events_url":"https://api.github.com/users/square/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/square/quotaservice","description":"The purpose of a quota service is to prevent cascading failures in micro-service environments. The service acts as a traffic cop, slowing down traffic where necessary to prevent overloading services. For this to work, remote procedure calls (RPCs) between services consult the quota service before making a call. The service isn’t strictly for RPCs between services, and can even be used to apply quotas to database calls, for example.","fork":false,"url":"https://api.github.com/repos/square/quotaservice","forks_url":"https://api.github.com/repos/square/quotaservice/forks","keys_url":"https://api.github.com/repos/square/quotaservice/keys{/key_id}","collaborators_url":"https://api.github.com/repos/square/quotaservice/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/square/quotaservice/teams","hooks_url":"https://api.github.com/repos/square/quotaservice/hooks","issue_events_url":"https://api.github.com/repos/square/quotaservice/issues/events{/number}","events_url":"https://api.github.com/repos/square/quotaservice/events","assignees_url":"https://api.github.com/repos/square/quotaservice/assignees{/user}","branches_url":"https://api.github.com/repos/square/quotaservice/branches{/branch}","tags_url":"https://api.github.com/repos/square/quotaservice/tags","blobs_url":"https://api.github.com/repos/square/quotaservice/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/square/quotaservice/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/square/quotaservice/git/refs{/sha}","trees_url":"https://api.github.com/repos/square/quotaservice/git/trees{/sha}","statuses_url":"https://api.github.com/repos/square/quotaservice/statuses/{sha}","languages_url":"https://api.github.com/repos/square/quotaservice/languages","stargazers_url":"https://api.github.com/repos/square/quotaservice/stargazers","contributors_url":"https://api.github.com/repos/square/quotaservice/contributors","subscribers_url":"https://api.github.com/repos/square/quotaservice/subscribers","subscription_url":"https://api.github.com/repos/square/quotaservice/subscription","commits_url":"https://api.github.com/repos/square/quotaservice/commits{/sha}","git_commits_url":"https://api.github.com/repos/square/quotaservice/git/commits{/sha}","comments_url":"https://api.github.com/repos/square/quotaservice/comments{/number}","issue_comment_url":"https://api.github.com/repos/square/quotaservice/issues/comments{/number}","contents_url":"https://api.github.com/repos/square/quotaservice/contents/{+path}","compare_url":"https://api.github.com/repos/square/quotaservice/compare/{base}...{head}","merges_url":"https://api.github.com/repos/square/quotaservice/merges","archive_url":"https://api.github.com/repos/square/quotaservice/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/square/quotaservice/downloads","issues_url":"https://api.github.com/repos/square/quotaservice/issues{/number}","pulls_url":"https://api.github.com/repos/square/quotaservice/pulls{/number}","milestones_url":"https://api.github.com/repos/square/quotaservice/milestones{/number}","notifications_url":"https://api.github.com/repos/square/quotaservice/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/square/quotaservice/labels{/name}","releases_url":"https://api.github.com/repos/square/quotaservice/releases{/id}","deployments_url":"https://api.github.com/repos/square/quotaservice/deployments","created_at":"2015-11-20T22:11:12Z","updated_at":"2019-02-11T03:37:19Z","pushed_at":"2019-02-11T22:20:35Z","git_url":"git://github.com/square/quotaservice.git","ssh_url":"git@github.com:square/quotaservice.git","clone_url":"https://github.com/square/quotaservice.git","svn_url":"https://github.com/square/quotaservice","homepage":"","size":15043,"stargazers_count":76,"watchers_count":76,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":18,"mirror_url":null,"archived":false,"open_issues_count":2,"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":18,"open_issues":2,"watchers":76,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/square/quotaservice/pulls/142"},"html":{"href":"https://github.com/square/quotaservice/pull/142"},"issue":{"href":"https://api.github.com/repos/square/quotaservice/issues/142"},"comments":{"href":"https://api.github.com/repos/square/quotaservice/issues/142/comments"},"review_comments":{"href":"https://api.github.com/repos/square/quotaservice/pulls/142/comments"},"review_comment":{"href":"https://api.github.com/repos/square/quotaservice/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/square/quotaservice/pulls/142/commits"},"statuses":{"href":"https://api.github.com/repos/square/quotaservice/statuses/7cf0558ecf2c397a8be38ad07ad329ea6236f19b"}},"author_association":"COLLABORATOR"}}
other: {"actor":{"display_login":"spenceral"}}