Jenkins parallel pipeline

I was very excited to know about the ‘parallel’ feature in Jenkins Pipeline, but, there are many gotchas while makingĀ  use of the pipeline feature (many of which are documented here: Jenkins Pipeline Example). After trying and reading a few different solutions, following worked for me (notice in screenshot that the browser jobs run in parallel !)

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        echo 'hello'
      }
    }
    stage('Test') {
      steps {
        script {
            def jobs = [:]
            def browsers = ["Chrome", "Firefox"]
            for (int i = 0; i < browsers.size(); i++) {
                def browser = browsers.get(i)
                def jobName = "printing $browser"
                jobs[jobName] = doJob(browser)
            }
            parallel jobs
        }
      }
    }
    stage('Deploy') {
      steps {
        echo 'deploying'
      }
    }
  }
}

def doJob(browser) {
    return {
        node {
            echo "testing in $browser"
        }
    }
}

HHVM notes

  • Impressive throughput improvements (>100%) with the app that I am working on.
  • phpinfo() doesn’t output what you would expect.
  • xhprof output_dir doesn’t get read from ini files, need to set that up in the constructor of XHProfRuns_Default.
  • Set hhvm.server.thread_count to a high value (>=MaxRequestWorkers), otherwise a few slow MySQL queries could bring the server to halt, minimal doc here: HHVM server architecture (worker thread => hhvm.server.thread_count). Suggest to keep it higher while JITing is happening.
  • If using Newrelic, tough luck!
    Unofficial Newrelic HHVM extension uses XHProf internally, so cannot get any data out of your own XHProf usage.
    The extension above relies on agent SDK that has no support for MySQL slow traces.
    Very low MySQL time in transactions.
    Strange traces in transactions.
  • CGI differences (apache_getenv not available use $_SERVER, SCRIPT_NAME will not be the same as REQUEST_URI).
  • Use realpath in imageftbox, relative paths for fonts don’t work.
  • Use Apache 2.4 as it has FastCGI support.
  • hhvm.log.header = true to have datetime in hhvm log.
  • HHVM log will also contain slow sql.
  • .hhbc was getting very huge, turned out it was due to Smarty file caching being enabled (the cached files were themselves php files that HHVM was compiling).
  • .hhbc file is sqlite(3) file that one can query (that is how I worked out the above).
  • High timeout values in memcached was leading to very high System CPU usage.
  • @ wasn’t suppressing (this could be Newrelic related)
  • Friendly folks in the hhvm IRC channel (get link from HHVM homepage), need to be online during daytime in the US.

casperjs output to html

Documenting what I had to do.

Used XSLT from here:
nosetest xslt

Problems and Fixes:

  1. Firefox was inserting “transformiix” as the root element, this caused the DOCTYPE to be spit out. I fixed by adding:
    doctype-public="-//W3C//DTD HTML 4.0//EN"/
    to 
    <xsl:output

    And removed the doctype declartion in the above xslt

  2. My version of casperjs was setting xml namespace to

    xmlns="http://www.w3.org/1999/xhtml

    After unsuccessfully trying to match the namespace in the xslt, I gave up and removed the namespace from the xunit xml, by

    sed -i 's@ xmlns="http://www.w3.org/1999/xhtml" @ @' "output.xml"
  3. Inserted the style into xml so can be rendered in the browser

    sed -i 's@ encoding="UTF-8"?>@ encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="nosetests.xslt" ?>@' "output.xml"
  4. Removed timestamp info from the xslt as it was in UTC timezone and could be very confusing when looking at the results (attempts to convert to my TZ in client were unsuccessful)

Backgrounded PHP jobs in ‘STOPPED’ state

This could be specific to the PHP package from Ubuntu. Please consider the following a disclaimer.

$ php -v
PHP 5.3.5-1ubuntu7.2 with Suhosin-Patch (cli) (built: May  2 2011 23:00:17) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans
 
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=11.04
DISTRIB_CODENAME=natty
DISTRIB_DESCRIPTION="Ubuntu 11.04"

I have a file with the following contents:

$ cat stdin.php
<?php
echo microtime(), "n";

and I was doing something like this (backgrounds the script. I was using a slightly modified version to make concurrent SOAP requests)

$ for i in `seq 1 2`; do echo $i; sleep 2s; php /tmp/stdin.php &gt;&gt; /tmp/k7.out & done
$ jobs
[1]-  Stopped                 php /tmp/stdin.php &gt;&gt; /tmp/k7.out
[2]+  Stopped                 php /tmp/stdin.php &gt;&gt; /tmp/k7.out

There are a few threads on the Internet relating to the issue and there are a few solutions.
First let us kill the ‘STOPPED’ jobs

$ kill %1
$ kill %2
[1]   Terminated              php /tmp/stdin.php &gt;&gt; /tmp/k7.out
$ jobs
[2]+  Terminated              php /tmp/stdin.php &gt;&gt; /tmp/k7.out

One of the solutions that worked for me was by supplying something to STDIN (perhaps STDIN was blocking, but then again, stream_set_blocking (STDIN, 0) wasn’t of much help).

$ for i in `seq 1 2`; do echo $i; sleep 2s; php /tmp/stdin.php &gt;&gt; /tmp/k7.out &lt; /dev/null & done

and you could simulate arguments

$ for i in `seq 1 2`; do echo $i; sleep 2s; echo arg1 arg2 | php /tmp/stdin.php &gt;&gt; /tmp/k7.out & done
$ tail -f k7.out
0.82262900 1316606606
array(2) {
  [0]=&gt;
  string(4) "arg1"
  [1]=&gt;
  string(4) "arg2"
}
0.83546500 1316606608
array(2) {
  [0]=&gt;
  string(4) "arg1"
  [1]=&gt;
  string(4) "arg2"
}

Checking for the existence of domains from commandline in Bash

while read line; do wget --quiet --spider --timeout=10 $line; if [ $? -ne 0 ]; then echo $line; fi; done < "/tmp/domains.txt" 
 
/tmp/domains.txt would hold the list of domain names separated by newline.
Note this is just a quick hack and not entirely reliable.

myisamcheck running out of tmp space

Recently I was running myisamcheck on an entire database housed inside a vserver. And, by default vserver mounts a 16MB ramfs on /tmp. This obviously is not an ideal solution when you are running a DB server that has a few tables that are around 20GB. So I had to specify a different directory for storing temporary files – that was on a partition with enough space – while running myisamcheck. To do that I had to make use of the –tmpdir parameter defined here.

Also, the way to increase the /tmp size inside a vserver seems to be this. I have not tested that solution yet.

Getting rid of MySQL Warning: Truncated incorrect DOUBLE value

If you come across a cryptic warning like this:

| Warning | 1292 | Truncated incorrect DOUBLE VALUE: 'xxxxxxx'

on running a MySQL query, it could be caused by using a numeric value against a CHAR/VARCHAR column.

---assuming `name` is a CHAR/VARCHAR column
---the following query might cause warnings
SELECT * FROM `t1` WHERE `name` IN (1, 2, 3);
---replace the above with this
SELECT * FROM `t1` WHERE `name` IN ('1', '2', '3');
--and the warnings are quite likely to go away

PHP as a replacement for sed/awk

I had gotten sick of not being able to do what I wanted to do with sed/awk – partly because I am not too familiar with those – and, was investigating replacements for those. Many people seem to be using perl and since I wasn’t too familiar with Perl as well, I started thinking about using PHP – which I do know. And, that served my needs brilliantly.

This is a simplistic version of my problem & a solution:
I can do the following to get the values for specific params (cid and oid in this case) for requests made, from my access logs:

k7@local:echo "http://example.com?cid=123&oid=435" | php -R 'preg_match("#.*cid=([^&]+)&oid=([^&]+)#",$argn, $matches);if(!empty($matches)) {echo $matches[1], " ", $matches[2], "n";}'
123 435

Regular Expression to check for comma separated list of Integers

//get rid of all kinds of spaces
$IDs = preg_replace('/s+/', '', $inputIDs);
if(!preg_match(''/^\d+$|^(\d+,)+\d+$/'', $IDs)) {
echo "Invalid Input";
}

You could use the validated IDs above in a SQL like the this:

SELECT * FROM t1 WHERE id IN($IDs)

Disclaimer: I am not going to be responsible for any kind of SQL injection resulting from using the snippet above.
updated 20-Mar-2013