Submit a function to a cluster

    Parameters
    ----------
    parent_id : str
        The ID of the group that the job is a part of.
    name : str
        The name of the job
    url : str
        The handler that can take the results (e.g., /beta_diversity/)
    func : function
        The function to execute. Any returns from this function will be
        serialized and deposited into Redis using the uuid for a key. This
        function should raise if the method fails.
    args : tuple or None
        Any args for ``func``
    kwargs : dict or None
        Any kwargs for ``func``

    Returns
    -------
    tuple, (str, str, AsyncResult)
        The job ID, parent ID and the IPython's AsyncResult object of the job

def _submit(ctx, parent_id, name, url, func, *args, **kwargs):
    """Submit a function to a cluster

    Parameters
    ----------
    parent_id : str
        The ID of the group that the job is a part of.
    name : str
        The name of the job
    url : str
        The handler that can take the results (e.g., /beta_diversity/)
    func : function
        The function to execute. Any returns from this function will be
        serialized and deposited into Redis using the uuid for a key. This
        function should raise if the method fails.
    args : tuple or None
        Any args for ``func``
    kwargs : dict or None
        Any kwargs for ``func``

    Returns
    -------
    tuple, (str, str, AsyncResult)
        The job ID, parent ID and the IPython's AsyncResult object of the job
    """
    parent_info = r_client.get(parent_id)
    if parent_info is None:
        parent_info = create_info('unnamed', 'group', id=parent_id)
        parent_id = parent_info['id']
        r_client.set(parent_id, json.dumps(parent_info))

    parent_pubsub_key = parent_id + ':pubsub'

    job_info = create_info(name, 'job', url=url, parent=parent_id,
                           context=ctx.name, store=True)
    job_info['status'] = 'Queued'
    job_id = job_info['id']

    with r_client.pipeline() as pipe:
        pipe.set(job_id, json.dumps(job_info))
        pipe.publish(parent_pubsub_key, json.dumps({'add': [job_id]}))
        pipe.execute()

    ar = ctx.bv.apply_async(_redis_wrap, job_info, func, *args, **kwargs)
    return job_id, parent_id, ar