Dealing with large jobs on Travis-CI

by Wojciech Adam Koszek   ⋅   Jul 25, 2016   ⋅   Menlo Park, CA

Below I explain problems you may run into when your continuous integration build starts to take a long time and I show some simple solutions for deadling with them.


I’m releasing all my projects through continuous integration, so I end up working with Travis-CI a lot. Travis provides a corresponding diagnostic page for each project I have linked to it from GitHub. For example one of my GitHub projects is here and its Travis-CI subpage would be here. If you look at the link format, you’ll understand what I mean. In there you can see what the output of your job was. Most of the jobs are fairly simple and finish within short period of time. For these jobs debugging the build steps is easy: just look at the console output and see what’s wrong. It’s what I do 95% of time. Below I give hints on how to handle 5% of other cases.

Bigger projects

While working on Sensorama for iOS I had to do something different, since it generates a lot of output from many tools. It has many dependencies on Ruby Gems and CocoaPods, which make it long-running as well. Unless you’re careful, you’ll make your life and Travis job debugging harder. For me debugging OSX/iOS projects is especially challenging, since it’s a flow of: bug, commit, verify cycles (for Linux/UNIX projects you can run Travis-CI environment in a Docker container).

Travis-CI limits for Open Source projects

Travis-CI is entirely free for Open Source, which I find great. Even though its run-time limits are pretty generous, they do exist:

  • time limit on jobs: which currently is set to 30 minutes.
  • 10 minute watchdog: if your job doesn’t output anything in this period, it will be killed.
  • size of the output files is limited to 4MB. If you run over it, your job will be killed.

How does the issue look like?

Example (from here):

+scan --workspace Sensorama.xcworkspace --scheme SensoramaTests
[08:12:08]: xcrun xcodebuild -list -workspace Sensorama.xcworkspace
No output has been received in the last 10m0s, this potentially indicates a
stalled build or something wrong with the build itself.
The build has been terminated

Another one (from here):

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator9.3.sdk -fasm-bloc
The log length has exceeded the limit of 4 MB (this usually means that the test suite is raising the same exception over and over).
The job has been terminated

How to deal with this stuff?

Prettifiers?

For XCode projects just pipe everything what comes from xcodebuild through xcpretty. If you’re using fastlane (and if not, you should), then the xcpretty is used automatically. Normally I don’t like the tools which obfuscate real command’s output, but in this case I had no choice. Also xcpretty makes the output understandable.

Output folding

Travis-CI has this cool undocumented feature called “output folding”. You can group lines of output which belong to the same group of commands. You’ll get them folded together and you don’t have to scroll through all the output thanks to it.

How to do it?

First of all, your config file .travis.yml for the script entry has to call 1 script. So for Sensorama I have:

language: objective-c
osx_image: xcode7.3
cache: cocoapods
rvm:
- 2.2
podfile: Sensorama/Podfile
script:
- ./scripts/travis_script.sh
#- ./scripts/script_with_folds
addons:
  ssh_known_hosts:
  - gitlab.com

If you want to give it a try, use script_with_folds, borrowed from here.

Then it’s pretty easy:

#!/bin/bash

travis_fold() {
  local action=$1
  local name=$2
  echo -en "travis_fold:${action}:${name}\r"
}

travis_fold start foo

echo "This line appears in the fold's 'header'"

echo "Stuff inside"

sleep 2

echo "More stuff"

travis_fold end foo

So every fold has to start with travis_fold:ACTION:name, where ACTION is either start or end, and the name is whatever you want.

Doing folds easily

For Sensorama I plan to use output folding a lot, so I’ve devised a simpler way to deal with this stuff:

TMP=/tmp/.travis_fold_name

# This is meant to be run from top-level dir. of sensorama-ios

travis_fold() {
  local action=$1
  local name=$2
  echo -en "travis_fold:${action}:${name}\r"
}

travis_fold_start() {
  travis_fold start $1
  echo $1
  /bin/echo -n $1 > $TMP
}

travis_fold_end() {
  travis_fold end `cat ${TMP}`
}

This is a more elaborate version of what I showed before, but it lets you to do:

(
  travis_fold_start BOOSTRAPPING
  ./build.sh bootstrap
  travis_fold_end
)

Without worrying whether the start and end tags for the fold are matched. One of the stupid mistakes I’ve made in one of the commits is that action and name mismatched, and then folding is broken.

Summary

For optimizing output logging I’d start from trying to limit job output. In cases where you can’t do it, try to use some output “compressors” and prettyfiers. Remember that these things add complexity and can sometimes make debugging harder, as they essentially obfuscate the output of original commands. At the end use output folding on Travis-CI.

Was this article useful? Let me know



Subscribe for updates

Once a month I send updates on the new content and hints for software engineers.



Liked it? Share it!


About the author: I'm Wojciech Adam Koszek. I like software, business and design. Poland native. In Bay Area since 2010.   More about me