Skip to content

Cache User (1 min) and Teams (1 hour) information#100

Merged
samrocketman merged 1 commit into
jenkinsci:masterfrom
artem-panchenko:apanchenko/add-more-caching
Apr 18, 2018
Merged

Cache User (1 min) and Teams (1 hour) information#100
samrocketman merged 1 commit into
jenkinsci:masterfrom
artem-panchenko:apanchenko/add-more-caching

Conversation

@artem-panchenko
Copy link
Copy Markdown
Contributor

Changes

The goal of this PR is to reduce requests rate to GitHub API by additional caching:

  • access token -> user info for a minute;
  • GH user -> teams info for an hour.

Rationale

If you have a service/bot which uses Jenkins and it makes a lot of API calls, fixed GitHub requests rate may quickly become a bottleneck.

Note

It's my first code written in Java, but I was able to compile it and test with Jenkins 2.107.1 :)
It works fine for our organization and helped us to dramatically decrease requests rate (approximately 10x times), that Jenkins makes to GitHub while authenticating API requests from our bot (just in case it uses python-jenkins client).

Call for HELP!

I'd really appreciate if someone helps me to groom the code and add/fix tests!

P.S.: I could miss something fundamental, so please share your thoughts on the issue I described and am trying to fix! Thank you!

@samrocketman
Copy link
Copy Markdown
Member

Thanks for your contribution. I’ll look it over and ask for more experienced eyes for help as well.

@samrocketman samrocketman requested a review from Wadeck April 10, 2018 16:31
@samrocketman
Copy link
Copy Markdown
Member

Can someone from @jenkinsci/code-reviewers take a look?

Copy link
Copy Markdown
Contributor

@Wadeck Wadeck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except the small comment on the changelog, the code seems good from my PoV.

Just consider that with this change, modification of GitHub team settings could take up to 1h to be seen inside Jenkins. OTOH it's already the case for org / repositories, so do not seem to bother users.

It's my first code written in Java

Good job :) even with anonymous class, generic handling, etc., you managed it!

Comment thread CHANGELOG.md Outdated
@@ -1,3 +1,7 @@
# Version 0.30 (Released Apr 1, 2018)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, the good practices is to provide the changelog in the PR, the maintainer will gather them to add to the CHANGELOG when the plugin will be released.

(the release process is not automatic after your PR is merged)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the changlog entry is fine but please remove the date.

Comment thread CHANGELOG.md Outdated
@@ -1,3 +1,7 @@
# Version 0.30 (Released Apr 1, 2018)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the changlog entry is fine but please remove the date.

@samrocketman
Copy link
Copy Markdown
Member

When you fix the changelog, please also squash your changes into a single commit.

Once that is done, I'll do some manual testing to validate your change does not adversely affect plugin upgrades. If that goes well, then I'll merge your change.

@Wadeck
Copy link
Copy Markdown
Contributor

Wadeck commented Apr 11, 2018

squash your changes

@samrocketman why do you ask for that ?

  • for your local testing purpose ?
    • you can just use the last commit on its branch
  • for the future merge ?
    • you can merge using squash directly inside GitHub

Perhaps I missed something :)

@samrocketman
Copy link
Copy Markdown
Member

squash your changes

There’s no technical requirement. It’s not even a merge requirement. I typically ask but if it’s not done, it does not stop me from merging it. Probably should have been more clear when asking.

@artem-panchenko artem-panchenko force-pushed the apanchenko/add-more-caching branch from cc4ad08 to 76623ea Compare April 12, 2018 20:15
@artem-panchenko
Copy link
Copy Markdown
Contributor Author

@samrocketman @Wadeck thank you for the feedback! I've updated the change log and squashed my commits as you requested.

@artem-panchenko artem-panchenko changed the title [WIP] Cache User (1 min) and Teams (1 hour) information Cache User (1 min) and Teams (1 hour) information Apr 12, 2018
@samrocketman
Copy link
Copy Markdown
Member

Thanks, I'm on a trip at the moment but will definitely look it over for testing. If you're curious I'll be using the jenkins-bootstrap-jervis project under my user to automatically configure the GitHub OAuth plugin (via settings.groovy).

@samrocketman samrocketman dismissed their stale review April 13, 2018 03:58

Will review again

Copy link
Copy Markdown
Member

@samrocketman samrocketman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

This pull request offers a speedup by a factor of 10 in my own configurations. I imagine, the more thorough the automated configuration, the better the speedup. thanks for this contribution.

Seconds to configure my Jenkins instance.

  • Before: 24.019s
  • After: 3.805s

Ref: https://github.com/samrocketman/jenkins-bootstrap-jervis

How did I build?

git fetch origin refs/pull/100/head
git checkout FETCH_HEAD -b PR-100
mvn clean package
Click to expand

Environment:

$ head -n1 /etc/issue
Ubuntu 16.04.4 LTS \n \l

$ uname -rms
Linux 4.13.0-38-generic x86_64

$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

$ mvn -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T08:41:47-08:00)
Maven home: /home/sam/usr/share/apache-maven-3.3.9
Java version: 1.8.0_131, vendor: Oracle Corporation
Java home: /home/sam/usr/share/java/jdk1.8.0_131/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.13.0-38-generic", arch: "amd64", family: "unix"

Before

Click to expand
$ time ./jervis_bootstrap.sh 
Waiting for http://localhost:8080/jnlpJars/jenkins-cli.jar to become available.ready.
Nothing changed.  Usage stats are not submitted to the Jenkins project.
Nothing changed.  Job "_jervis_generator" already exists.
Nothing changed.  Job "__clean_abandoned_branches_multibranch" already exists.
Nothing changed.  View "Welcome" already exists.
Nothing changed.  View "GitHub Organizations" already exists.
Nothing changed.  View "Maintenance" already exists.
Nothing changed.  Primary view already set to "Welcome".
Nothing changed.  Markup Formatter already configured.
Nothing changed.  Docker agent credentials already configured.
Nothing changed.  Agent -> master security already disabled.
Nothing changed.  Job DSL script security already disabled.
Nothing changed.  Agent Protocols already configured: [JNLP4-connect, Ping]
Nothing changed.  Global Jenkinsfile already configured.
Nothing changed.  Global Jenkinsfile script already approved.
Nothing changed.  Master already restricts jobs.
Nothing changed.  Admin groovy scripts already approved.
Nothing changed.  Grape repository config used by @Grab already configured.
Nothing changed.  Jenkins settings already configured.
Nothing changed.  github-token credentials already configured.
Nothing changed.  github-user-and-token credentials already configured.
Nothing changed.  webhook-shared-secret credentials already configured.
Nothing changed.  Pipeline Global Shared Libraries already configured.
Nothing changed.  GitHub plugin already configured.
Nothing changed.  Already using random least loaded provisioning strategy for docker.
Configured Yet Another Docker cloud docker-local
Nothing changed.  GitHub security realm already configured.
Jenkins is ready.  Visit http://localhost:8080/
User: samrocketman

real	0m24.019s
user	0m1.324s
sys	0m0.367s

After

Click to expand
$ time ./jervis_bootstrap.sh 
Waiting for http://localhost:8080/jnlpJars/jenkins-cli.jar to become available.ready.
Nothing changed.  Usage stats are not submitted to the Jenkins project.
Nothing changed.  Job "_jervis_generator" already exists.
Nothing changed.  Job "__clean_abandoned_branches_multibranch" already exists.
Nothing changed.  View "Welcome" already exists.
Nothing changed.  View "GitHub Organizations" already exists.
Nothing changed.  View "Maintenance" already exists.
Nothing changed.  Primary view already set to "Welcome".
Nothing changed.  Markup Formatter already configured.
Nothing changed.  Docker agent credentials already configured.
Nothing changed.  Agent -> master security already disabled.
Nothing changed.  Job DSL script security already disabled.
Nothing changed.  Agent Protocols already configured: [JNLP4-connect, Ping]
Nothing changed.  Global Jenkinsfile already configured.
Nothing changed.  Global Jenkinsfile script already approved.
Nothing changed.  Master already restricts jobs.
Nothing changed.  Admin groovy scripts already approved.
Nothing changed.  Grape repository config used by @Grab already configured.
Nothing changed.  Jenkins settings already configured.
Nothing changed.  github-token credentials already configured.
Nothing changed.  github-user-and-token credentials already configured.
Nothing changed.  webhook-shared-secret credentials already configured.
Nothing changed.  Pipeline Global Shared Libraries already configured.
Nothing changed.  GitHub plugin already configured.
Nothing changed.  Already using random least loaded provisioning strategy for docker.
Configured Yet Another Docker cloud docker-local
Nothing changed.  GitHub security realm already configured.
Jenkins is ready.  Visit http://localhost:8080/
User: samrocketman

real	0m3.805s
user	0m1.310s
sys	0m0.393s

@samrocketman samrocketman merged commit 715be7a into jenkinsci:master Apr 18, 2018
@artem-panchenko
Copy link
Copy Markdown
Contributor Author

Thank you for the support of the PR! I'm very glad that the patch has got into master!

P.S. do you guys know when a new version of the plugin is going to be released? :)

@samrocketman
Copy link
Copy Markdown
Member

Looking at merging one more PR before releasing. But if it's not prepared in a week or so I can cut a new release and let it go to the next. I try to make it so that a release has a couple improvements. But sometimes it only has one improvement 😄 .

@vrenjith
Copy link
Copy Markdown

Any updates on when we are releasing this?

@samrocketman
Copy link
Copy Markdown
Member

@artem-panchenko @vrenjith github-oauth 0.31 was just released which is the first release that includes this patch.

@mihir-io
Copy link
Copy Markdown

@artem-panchenko @samrocketman Is there any way to add the option to configure the cache expiration time?

@jamesrwhite
Copy link
Copy Markdown

Hi, is there anyway to force this cache to be cleared? I feel this should be mentioned on the wiki as well really as it took me a while to discover this caching even existed.

My use case is I'm using matrix auth to set permissions based on the teams a user is in. If they try and access Jenkins whilst not in the required team, then I add them to that team, they then have to wait an hour before this change takes effect which isn't ideal.

@js-timbirkett
Copy link
Copy Markdown

@jamesrwhite - we've hit this too and it's a bit frustrating... Tried:

import org.jenkinsci.plugins.*
GithubAuthenticationToken.clearCaches()

In the script console but it didn't seem to resolve the issue. @mihir-io - cache configuration would be a dream come true.

@samrocketman
Copy link
Copy Markdown
Member

samrocketman commented Jul 16, 2020

@jamesrwhite @js-timbirkett
Here is how I do it in my code base. It works with Job DSL code. It's the first code I run before detecting admin permissions.

/**
  * https://github.com/samrocketman MIT License
  * Clear the authorization cache so that we can immediately discover new
  * permissions for generating a job.  This will wipe and create a fresh cache
  * when a user generates a job.
  *
  * Source code paths
  *     GitHubClientCacheOps https://github.com/jenkinsci/github-plugin/blob/master/src/main/java/org/jenkinsci/plugins/github/internal/GitHubClientCacheOps.java
  *     GitHubLoginFunction  https://github.com/jenkinsci/github-plugin/blob/master/src/main/java/org/jenkinsci/plugins/github/internal/GitHubLoginFunction.java
  *     GitHubPluginConfig   https://github.com/jenkinsci/github-plugin/blob/master/src/main/java/org/jenkinsci/plugins/github/config/GitHubPluginConfig.java
  *     GitHubServerConfig   https://github.com/jenkinsci/github-plugin/blob/master/src/main/java/org/jenkinsci/plugins/github/config/GitHubServerConfig.java
  *
  * Additional Information:
  *     Usage of uberClassLoader and getExtensionList are because of
  *     limitations in the Job DSL plugin.  These are helper functions provided
  *     by Jenkins core which helps work around classloader limitations (i.e.
  *     classes not available to import)
  */
void wipeAuthorizationCache() {
    Class github_cache_ops = Jenkins.instance.pluginManager.uberClassLoader.loadClass('org.jenkinsci.plugins.github.internal.GitHubClientCacheOps')
    List github_server_configs = Jenkins.instance.getExtensionList('org.jenkinsci.plugins.github.config.GitHubPluginConfig')[0].configs
    github_server_configs.each { github_server_config ->
        github_cache_ops.toCacheDir().apply(github_server_config).delete()
        github_server_config.setCachedClient(null)
        def github_login_function = Jenkins.instance.pluginManager.uberClassLoader.loadClass('org.jenkinsci.plugins.github.internal.GitHubLoginFunction').newInstance()
        github_server_config.setCachedClient(github_login_function.apply(github_server_config))
    }
}
wipeAuthorizationCache()

And here's an example checking for admin access (for example webhook registration).

import com.cloudbees.jenkins.GitHubRepositoryName

// example dummy values for https://github.com/jenkinsci/github-oauth-plugin
String host = 'github.com'
String namespace = 'jenkinsci'
String repo = 'github-oauth-plugin'

if(!(new GitHubRepositoryName(host, namespace, repo)).resolveOne()?.hasAdminAccess()) {
    throw new Exception('''
    |ERROR: please make Jenkins an admin of your repository.  Otherwise, webhooks can't be automatically registered.
    '''.stripMargin().trim())
}

@samrocketman
Copy link
Copy Markdown
Member

@artem-panchenko I'm not sure why clearCaches() doesn't work. It didn't for me when I rolled it out so this is my workaround for now. Any idea why it doesn't work to clear the cache?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants