{
 "metadata": {
  "name": "",
  "signature": "sha256:481e128e553ec13e039f3e3f5e567cc3caffe391b78b9821ee883fb8770ebc82"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Background Jobs"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We start by loading the `backgroundjobs` library and defining a few trivial functions to illustrate things with."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from __future__ import print_function\n",
      "from IPython.lib import backgroundjobs as bg\n",
      "\n",
      "import sys\n",
      "import time\n",
      "\n",
      "def sleepfunc(interval=2, *a, **kw):\n",
      "    args = dict(interval=interval,\n",
      "                args=a,\n",
      "                kwargs=kw)\n",
      "    time.sleep(interval)\n",
      "    return args\n",
      "\n",
      "def diefunc(interval=2, *a, **kw):\n",
      "    time.sleep(interval)\n",
      "    raise Exception(\"Dead job with interval %s\" % interval)\n",
      "\n",
      "def printfunc(interval=1, reps=5):\n",
      "    for n in range(reps):\n",
      "        time.sleep(interval)\n",
      "        print('In the background...', n)\n",
      "        sys.stdout.flush()\n",
      "    print('All done!')\n",
      "    sys.stdout.flush()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now, we can create a job manager (called simply `jobs`) and use it to submit new jobs.\n",
      "<br>\n",
      "Run the cell below and wait a few seconds for the whole thing to finish, until you see the \"All done!\" printout."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "jobs = bg.BackgroundJobManager()\n",
      "\n",
      "# Start a few jobs, the first one will have ID # 0\n",
      "jobs.new(sleepfunc, 4)\n",
      "jobs.new(sleepfunc, kw={'reps':2})\n",
      "jobs.new('printfunc(1,3)')\n",
      "\n",
      "# This makes a couple of jobs which will die.  Let's keep a reference to\n",
      "# them for easier traceback reporting later\n",
      "diejob1 = jobs.new(diefunc, 1)\n",
      "diejob2 = jobs.new(diefunc, 2)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Starting job # 0 in a separate thread.\n",
        "Starting job # 2 in a separate thread.\n",
        "Starting job # 3 in a separate thread.\n",
        "Starting job # 4 in a separate thread.\n",
        "Starting job # 5 in a separate thread.\n"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "You can check the status of your jobs at any time:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "jobs.status()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "In the background... 0\n",
        "Running jobs:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "0 : <function sleepfunc at 0x102cc6848>\n",
        "2 : <function sleepfunc at 0x102cc6848>\n",
        "3 : printfunc(1,3)\n",
        "5 : <function diefunc at 0x102cc68c0>\n",
        "\n",
        "Dead jobs:\n",
        "4 : <function diefunc at 0x102cc68c0>\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "For any completed job, you can get its result easily:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "jobs[0].result\n",
      "j0 = jobs[0]\n",
      "j0.join?"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 4
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "You can get the traceback of any dead job.  Run the line\n",
      "below again interactively until it prints a traceback (check the status\n",
      "of the job):\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print \"Status of diejob1:\", diejob1.status\n",
      "diejob1.traceback()  # jobs.traceback(4) would also work here, with the job number"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "In the background... 1\n",
        "In the background... 2\n",
        "All done!\n"
       ]
      },
      {
       "ename": "SyntaxError",
       "evalue": "invalid syntax (<ipython-input-5-a90bd59af669>, line 1)",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-5-a90bd59af669>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m    print \"Status of diejob1:\", diejob1.status\u001b[0m\n\u001b[0m                             ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This will print all tracebacks for all dead jobs:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "jobs.traceback()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Traceback for: <BackgroundJob #4: <function diefunc at 0x102cc68c0>>\n",
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n",
        "\u001b[0;31mException\u001b[0m                                 Traceback (most recent call last)\n",
        "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/lib/backgroundjobs.pyc\u001b[0m in \u001b[0;36mcall\u001b[0;34m(self)\u001b[0m\n",
        "\u001b[1;32m    489\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m    490\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mcall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m--> 491\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0m\n",
        "\u001b[0;32m<ipython-input-1-7391f8ae281b>\u001b[0m in \u001b[0;36mdiefunc\u001b[0;34m(interval, *a, **kw)\u001b[0m\n",
        "\u001b[1;32m     14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdiefunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minterval\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m     15\u001b[0m     \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minterval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m---> 16\u001b[0;31m     \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Dead job with interval %s\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0minterval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0m\u001b[1;32m     17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m     18\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mprintfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minterval\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreps\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\n",
        "\u001b[0;31mException\u001b[0m: Dead job with interval 1\n",
        "\n",
        "Traceback for: <BackgroundJob #5: <function diefunc at 0x102cc68c0>>\n",
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n",
        "\u001b[0;31mException\u001b[0m                                 Traceback (most recent call last)\n",
        "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/lib/backgroundjobs.pyc\u001b[0m in \u001b[0;36mcall\u001b[0;34m(self)\u001b[0m\n",
        "\u001b[1;32m    489\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m    490\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mcall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m--> 491\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0m\n",
        "\u001b[0;32m<ipython-input-1-7391f8ae281b>\u001b[0m in \u001b[0;36mdiefunc\u001b[0;34m(interval, *a, **kw)\u001b[0m\n",
        "\u001b[1;32m     14\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdiefunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minterval\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m     15\u001b[0m     \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minterval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m---> 16\u001b[0;31m     \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Dead job with interval %s\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0minterval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0m\u001b[1;32m     17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m     18\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mprintfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minterval\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreps\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\n",
        "\u001b[0;31mException\u001b[0m: Dead job with interval 2\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 6
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The job manager can be flushed of all completed jobs at any time:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "jobs.flush()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Flushing 3 Completed jobs.\n",
        "Flushing 2 Dead jobs.\n"
       ]
      }
     ],
     "prompt_number": 7
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "After that, the status is simply empty:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [
      "jobs.status()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 8
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "It's easy to wait on a job:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "j = jobs.new(sleepfunc, 2)\n",
      "print(\"Will wait for j now...\")\n",
      "sys.stdout.flush()\n",
      "j.join()\n",
      "print(\"Result from j:\")\n",
      "j.result"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Starting job # 0 in a separate thread.\n",
        "Will wait for j now...\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Result from j:\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 9,
       "text": [
        "{'args': (), 'interval': 2, 'kwargs': {}}"
       ]
      }
     ],
     "prompt_number": 9
    }
   ],
   "metadata": {}
  }
 ]
}