3

This is an extension or variant of How to configure Git post commit hook

The problem I have is that I do not want one build per commit. What I want instead is trigger a single instance of a build at a time. While that single instance is running, new requests can accumulate, but they should be consolidated into a single new build once the current build completes.

Obviously, the triggering should be on git revisions which are meaningfully related, usually from the same branch, and the build should always execute on the triggering revision closest to HEAD (does that make sense?).

So, for the sake of this question, assume everyone is pushing to master, and I place a git hook to trigger the build. How do I make it so that pending requests are merged into a single requests instead of queuing up as separate builds?

This behavior is trivially configurable by using polling, but I don't want to use polling for a variety of unrelated reasons (large number of jobs + need to poll multiple repos consumed by a single job).

Jenkins parameterized job that only queues one build offers one possibility: Use a "launcher" job which terminates quickly and launches the actual working job with "Combine Queued git hashes". The problem with this approach is that the launcher job needs to check out the repo prior to launching the working job. Given a large git repo, this introduces an unacceptable delay.

Community
  • 1
  • 1
Christian Goetze
  • 2,254
  • 3
  • 34
  • 51
  • One thought that occurred to me is that I allow the jobs to accumulate in the queue, and whenever the job runs, it totally ignores the git commit triggering the run and just checks out HEAD, and then I run a little system groovy script which cleans out the queue of all requests older than the launch time of the job, thereby leaving any new requests which came in after launching the build, but before running the script on the queue, so we don't miss a run even if no more new requests come in... – Christian Goetze Oct 03 '16 at 21:59
  • The trouble with the queue cleanup is that until the new run is triggered, hundreds of new requests can pile up, rendering the job history on the left quite useless. – Christian Goetze Oct 03 '16 at 22:12
  • Yet another idea is to not trigger the long running singleton job directly, but instead trigger a small system groovy job which in turn manages the queue of the long running job. On every invocation, it would check if the actual job is running, if not, launch it. If there queue is empty, enqueue, otherwise empty the queue and enqueue the new job. – Christian Goetze Oct 03 '16 at 23:34

1 Answers1

1

Do you have a requirement of triggering builds via git hooks?

Because if not, you could easily get the desired behaviour changing your job trigger to repository polling with a decent timeout. Let's say five minutes, which gives enough time for these new revisions to stack up and be built at once.

Also you could use Throttle Concurrent Builds plugin and add constraints that avoid concurrent builds.

EDIT: There's also the option of keeping your git hooks but adding a Quiet Period. Which is a Jenkins core feature, reachable through the Manage Jenkins section.

EDIT2: When I've read your new comments I thought about Parametrized Scheduler Plugin and adding a parameter to specify the repository URL, but this is not polling for changes it's scheduling builds periodically, which is not what you want.

In the light of the new requirements, I would do something that sounds a bit like a Jerry Rig: I would create another job called your-project-executor this guy would build periodically (every 2 minutes or so) and run a shell script that would have a big if-else block, this would git fetch and check for changes in different pre-defined repositories, if a given repository has changes, then this would trigger your current job with the required parameters (REPO_URL, etc...).

To check for changes you could store HEAD current revision hash in a properties file in the executor job workspace and then compare that to the output of git rev-parse HEAD.

EDIT3: Example of setting the build rate: enter image description here This would consume your queue once per hour.

Rogério Peixoto
  • 2,176
  • 2
  • 23
  • 31
  • The main issue is I need to poll multiple repos, since the job consumes multiple repos. – Christian Goetze Oct 05 '16 at 18:11
  • Another use case is a job being triggered downstream of another job. I know that for this case, there is a checkbox called "Combine Queued git hashes" which does what I want, but implementing that for a remotely triggered build means doing two checkouts (one for the job that runs the actual job with Combined Queued git hashes, then one for the actual job). Think having to check out a 15G git repo.... – Christian Goetze Oct 05 '16 at 18:14
  • One thing to keep in mind is that you don't need to clone the repo to check if there's new changes to it. You just need to fetch the indexes... – Rogério Peixoto Oct 05 '16 at 18:43
  • Yes, and I think that's how polling works. My comment on checking out was to explain why the "Combine Queued git hashes" thing doesn't solve my problem. What I really want is a way to incorporate ""Combine Queued git hashes" into the remote triggering directly, not just as part of running a subproject. I guess the bottom line is that someone needs to write a new plugin :) – Christian Goetze Oct 05 '16 at 19:12
  • As for your EDIT2 comment: I don't see how it will work when the target project is already executing. Will it just not queue up a new request? Will it inspect the queue and remove all previous entries prior to queuing up a new one? I think I will need to do something like that... – Christian Goetze Oct 05 '16 at 19:16
  • If you use Throttle Concurrent Builds, and set a constraint to 1 job instance running at a the time... the other job calls from the executor will queue... you can increase the polling interval to have less job calls per new changes/commits. – Rogério Peixoto Oct 05 '16 at 20:03
  • But will it consolidate the queue? – Christian Goetze Oct 05 '16 at 22:19
  • If you throttle the builds rate, they will consolidate the queue for each execution... Do you mean you want to git squash the commits before running the job? – Rogério Peixoto Oct 07 '16 at 14:28
  • I think that the consolidation only occurs when polling is used. No, I don't want to squash, just skip the latest... – Christian Goetze Oct 12 '16 at 20:12