def managed_task(task_function):
  """Decorator to manage task methods.

  This records the status of the task in an entity and raises the
  deferred.PermanentTaskFailure exception to prevent tasks from repeating upon
  failure. In such cases, the exception message is recorded to the entity.

  Args:
    task_function: function, to be managed by the decorator.

  Returns:
    Wrapped function.

  Raises:
    deferred.PermanentTaskFailure: if anything at all goes wrong.
  """
  @functools.wraps(task_function)
  def wrapper(*args, **kwargs):
    """Wrapper for managed task decorator."""
    status_entity = bootstrap_status_model.BootstrapStatus.get_or_insert(
        task_function.__name__)
    status_entity.description = _TASK_DESCRIPTIONS.get(
        task_function.__name__, task_function.__name__)
    status_entity.timestamp = datetime.datetime.utcnow()
    try:
      task_function(*args, **kwargs)
      status_entity.success = True
      status_entity.details = None
      status_entity.put()
    except Exception as e:
      status_entity.success = False
      status_entity.details = '{} {}'.format(str(type(e)), str(e))
      status_entity.put()
      raise deferred.PermanentTaskFailure(
          'Task {} failed; error: {}'.format(
              task_function.__name__, status_entity.details))

  return wrapper