def update_liveaction_status(
    status=None,
    result=None,
    context=None,
    end_timestamp=None,
    liveaction_id=None,
    runner_info=None,
    liveaction_db=None,
    publish=True,
):
    """
    Update the status of the specified LiveAction to the value provided in
    new_status.

    The LiveAction may be specified using either liveaction_id, or as an
    liveaction_db instance.
    """

    if (liveaction_id is None) and (liveaction_db is None):
        raise ValueError(
            "Must specify an liveaction_id or an liveaction_db when "
            "calling update_LiveAction_status"
        )

    if liveaction_db is None:
        liveaction_db = get_liveaction_by_id(liveaction_id)

    if status not in LIVEACTION_STATUSES:
        raise ValueError(
            'Attempting to set status for LiveAction "%s" '
            'to unknown status string. Unknown status is "%s"' % (liveaction_db, status)
        )

    if (
        result
        and cfg.CONF.system.validate_output_schema
        and status == LIVEACTION_STATUS_SUCCEEDED
    ):
        action_db = get_action_by_ref(liveaction_db.action)
        runner_db = get_runnertype_by_name(action_db.runner_type["name"])
        result, status = output_schema.validate_output(
            runner_db.output_schema,
            action_db.output_schema,
            result,
            status,
            runner_db.output_key,
        )

    # If liveaction_db status is set then we need to decrement the counter
    # because it is transitioning to a new state
    if liveaction_db.status:
        get_driver().dec_counter("action.executions.%s" % (liveaction_db.status))

    # If status is provided then we need to increment the timer because the action
    # is transitioning into this new state
    if status:
        get_driver().inc_counter("action.executions.%s" % (status))

    extra = {"liveaction_db": liveaction_db}
    LOG.debug(
        'Updating ActionExection: "%s" with status="%s"',
        liveaction_db.id,
        status,
        extra=extra,
    )

    # If liveaction is already canceled, then do not allow status to be updated.
    if (
        liveaction_db.status == LIVEACTION_STATUS_CANCELED
        and status != LIVEACTION_STATUS_CANCELED
    ):
        LOG.info(
            'Unable to update ActionExecution "%s" with status="%s". '
            "ActionExecution is already canceled.",
            liveaction_db.id,
            status,
            extra=extra,
        )
        return liveaction_db

    old_status = liveaction_db.status
    liveaction_db.status = status

    if result:
        liveaction_db.result = result

    if context:
        liveaction_db.context.update(context)

    if end_timestamp:
        liveaction_db.end_timestamp = end_timestamp

    if runner_info:
        liveaction_db.runner_info = runner_info

    # TODO: This is not efficient. Perform direct partial update and only update
    # manipulated fields
    liveaction_db = LiveAction.add_or_update(liveaction_db)

    LOG.debug("Updated status for LiveAction object.", extra=extra)

    if publish and status != old_status:
        LiveAction.publish_status(liveaction_db)
        LOG.debug("Published status for LiveAction object.", extra=extra)

    return liveaction_db

    Update the status of the specified LiveAction to the value provided in
    new_status.

    The LiveAction may be specified using either liveaction_id, or as an
    liveaction_db instance.
    
st2common/st2common/util/action_db.py